Skip to content

Commit

Permalink
Showing 32 changed files with 344 additions and 346 deletions.
11 changes: 7 additions & 4 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -841,8 +841,11 @@ public IRubyObject runInterpreter(ThreadContext context, Node rootNode, IRubyObj
assert self == getTopSelf();
final JRubyTruffleInterface truffleContext = getTruffleContext();
Main.printTruffleTimeMetric("before-run");
truffleContext.execute((RootNode) rootNode);
Main.printTruffleTimeMetric("after-run");
try {
truffleContext.execute((RootNode) rootNode);
} finally {
Main.printTruffleTimeMetric("after-run");
}
return getNil();
} else {
return interpreter.execute(this, rootNode, self);
@@ -890,7 +893,7 @@ public JRubyTruffleInterface getTruffleContext() {
}

private JRubyTruffleInterface loadTruffle() {
Main.printTruffleTimeMetric("before-load-truffle-context");
Main.printTruffleTimeMetric("before-load-context");

final Class<?> clazz;

@@ -909,7 +912,7 @@ private JRubyTruffleInterface loadTruffle() {
throw new RuntimeException("Error while calling the constructor of Truffle's RubyContext", e);
}

Main.printTruffleTimeMetric("after-load-truffle-context");
Main.printTruffleTimeMetric("after-load-context");

return truffleContext;
}
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/util/cli/Options.java
Original file line number Diff line number Diff line change
@@ -273,7 +273,7 @@ public class Options {
public static final Option<Boolean> TRUFFLE_CALL_GRAPH = bool(TRUFFLE, "truffle.callgraph", false, "Maintain a call graph.");
public static final Option<String> TRUFFLE_CALL_GRAPH_WRITE = string(TRUFFLE, "truffle.callgraph.write", "File to write the call garph to on exit.");

public static final Option<Boolean> TRUFFLE_GRAAL_WARNING_UNLESS = bool(TRUFFLE, "truffle.graal.warn_unless", false, "Warn unless the JVM has the Graal compiler.");
public static final Option<Boolean> TRUFFLE_GRAAL_WARNING_UNLESS = bool(TRUFFLE, "truffle.graal.warn_unless", true, "Warn unless the JVM has the Graal compiler.");

public static String dump() {
return "# JRuby configuration options with current values\n" +
1 change: 1 addition & 0 deletions spec/truffle/tags/library/zlib/inflate/finish_tags.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
fails:Zlib::Inflate#finish inflates chunked data
slow:Zlib::Inflate#finish
2 changes: 2 additions & 0 deletions spec/truffle/tags/library/zlib/inflate/inflate_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
fails:Zlib::Inflate#inflate works in pass-through mode, once finished
fails:Zlib::Inflate.inflate properly handles excessive data, byte-by-byte
fails:Zlib::Inflate#inflate without break inflates chunked data
slow:Zlib::Inflate#inflate with break
slow:Zlib::Inflate#inflate without break
7 changes: 2 additions & 5 deletions test/truffle/integration/rack-server/rack-server.rb
Original file line number Diff line number Diff line change
@@ -7,16 +7,13 @@
# GNU Lesser General Public License version 2.1

require 'rack'

# bin/jruby bin/gem install rack
# jt run -Ilib/ruby/gems/shared/gems/rack-1.6.1/lib simple-rack-server.rb


class Example
def call(env)
return [200, {}, ["Hello Rack!\n"]]
end
end

Rack::Handler::WEBrick.run(
Example.new,
:Port => 8080
3 changes: 0 additions & 3 deletions test/truffle/integration/sinatra-server/sinatra-server.rb
Original file line number Diff line number Diff line change
@@ -8,9 +8,6 @@

require 'sinatra'

# bin/jruby bin/gem install sinatra
# jt run -Ilib/ruby/gems/shared/gems/rack-1.6.1/lib -Ilib/ruby/gems/shared/gems/tilt-2.0.1/lib -Ilib/ruby/gems/shared/gems/rack-protection-1.5.3/lib -Ilib/ruby/gems/shared/gems/sinatra-1.4.6/lib test/truffle/simple-sinatra-server.rb

set :port, 8080

get '/' do
17 changes: 0 additions & 17 deletions test/truffle/metrics/client.rb

This file was deleted.

21 changes: 21 additions & 0 deletions test/truffle/metrics/codeload.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
5_000.times do |n|
eval %{
def foo#{n}(a, b, c)
if a == b
a + b + c # comments
else
a.foo + b.foo + c.foo
end
end
class Foo#{n}
def bar#{n}
[#{n}, #{n} + 1, #{n} + 2]
end
def baz#{n}
{a: #{n}, b: #{n + 1}, c: #{n + 2}}
end
end
}
end
27 changes: 0 additions & 27 deletions test/truffle/metrics/count-classes.rb

This file was deleted.

14 changes: 0 additions & 14 deletions test/truffle/metrics/jruby-timed

This file was deleted.

104 changes: 104 additions & 0 deletions test/truffle/metrics/mandelbrot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright © 2004-2013 Brent Fulgham
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of "The Computer Language Benchmarks Game" nor the name
# of "The Computer Language Shootout Benchmarks" nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# The Computer Language Benchmarks Game
# http://benchmarksgame.alioth.debian.org
#
# contributed by Karl von Laudermann
# modified by Jeremy Echols
# modified by Detlef Reichl
# modified by Joseph LaFata
# modified by Peter Zotov

# http://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=yarv&id=3

def mandelbrot(size)
sum = 0

byte_acc = 0
bit_num = 0

y = 0
while y < size
ci = (2.0*y/size)-1.0

x = 0
while x < size
zrzr = zr = 0.0
zizi = zi = 0.0
cr = (2.0*x/size)-1.5
escape = 0b1

z = 0
while z < 50
tr = zrzr - zizi + cr
ti = 2.0*zr*zi + ci
zr = tr
zi = ti
# preserve recalculation
zrzr = zr*zr
zizi = zi*zi
if zrzr+zizi > 4.0
escape = 0b0
break
end
z += 1
end

byte_acc = (byte_acc << 1) | escape
bit_num += 1

# Code is very similar for these cases, but using separate blocks
# ensures we skip the shifting when it's unnecessary, which is most cases.
if (bit_num == 8)
#print byte_acc.chr
sum ^= byte_acc
byte_acc = 0
bit_num = 0
elsif (x == size - 1)
byte_acc <<= (8 - bit_num)
#print byte_acc.chr
sum ^= byte_acc
byte_acc = 0
bit_num = 0
end
x += 1
end
y += 1
end

sum
end

start = Time.now

while Time.now - start < 30
mandelbrot(25)
end
67 changes: 0 additions & 67 deletions test/truffle/metrics/minimum-heap.rb

This file was deleted.

21 changes: 0 additions & 21 deletions test/truffle/metrics/one-request.rb

This file was deleted.

55 changes: 0 additions & 55 deletions test/truffle/metrics/process-times.rb

This file was deleted.

35 changes: 0 additions & 35 deletions test/truffle/metrics/total-allocation.rb

This file was deleted.

7 changes: 0 additions & 7 deletions test/truffle/metrics/with-client.sh

This file was deleted.

169 changes: 153 additions & 16 deletions tool/jt.rb
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
JDEBUG = "-J-agentlib:jdwp=transport=dt_socket,server=y,address=#{JDEBUG_PORT},suspend=y"
JDEBUG_TEST = "-Dmaven.surefire.debug=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=#{JDEBUG_PORT} -Xnoagent -Djava.compiler=NONE"
JEXCEPTION = "-Xtruffle.exceptions.print_java=true"
METRICS_REPS = 10

# wait for sub-processes to handle the interrupt
trap(:INT) {}
@@ -142,11 +143,26 @@ module ShellUtils
private

def raw_sh(*args)
puts "$ #{printable_cmd(args)}"
if args.last == :no_print_cmd
args.pop
else
puts "$ #{printable_cmd(args)}"
end
continue_on_failure = false
if args.last == :continue_on_failure
args.pop
continue_on_failure = true
end
result = system(*args)
unless result
$stderr.puts "FAILED (#{$?}): #{printable_cmd(args)}"
exit $?.exitstatus
if result
true
else
if continue_on_failure
false
else
$stderr.puts "FAILED (#{$?}): #{printable_cmd(args)}"
exit $?.exitstatus
end
end
end

@@ -245,8 +261,9 @@ def help
puts 'jt bench compare [benchmarks] run a set of benchmarks and compare against a reference point'
puts ' benchmarks can be any benchmarks or group of benchmarks supported'
puts ' by bench9000, eg all, classic, chunky, 3, 5, 10, 15 - default is 5'
puts 'jt findbugs run findbugs'
puts 'jt findbugs report run findbugs and generate an HTML report'
puts 'jt metrics alloc ... how much memory is allocated running a program (use -X-T to test normal JRuby on this metric and others)'
puts 'jt metrics minheap ... what is the smallest heap you can use to run an application'
puts 'jt metrics time ... how long does it take to run a command, broken down into different phases'
puts 'jt install ..../graal/mx/suite.py install a JRuby distribution into an mx suite'
puts
puts 'you can also put build or rebuild in front of any command'
@@ -293,7 +310,11 @@ def rebuild

def run(*args)
env_vars = args.first.is_a?(Hash) ? args.shift : {}
jruby_args = ['-X+T', "-Xtruffle.core.load_path=#{JRUBY_DIR}/truffle/src/main/ruby"]
jruby_args = [
'-X+T',
"-Xtruffle.core.load_path=#{JRUBY_DIR}/truffle/src/main/ruby",
'-Xtruffle.graal.warn_unless=false'
]

{ '--asm' => '--graal', '--igv' => '--graal' }.each_pair do |arg, dep|
args.unshift dep if args.include?(arg)
@@ -536,16 +557,132 @@ def bench(command, *args)
end
raw_sh env_vars, "ruby", *bench_args, *args
end

def findbugs(report=nil)
case report
when 'report'
sh 'tool/truffle-findbugs.sh', '--report'
sh 'open', 'truffle-findbugs-report.html'
when nil
sh 'tool/truffle-findbugs.sh'

def metrics(command, *args)
case command
when 'alloc'
metrics_alloc *args
when 'minheap'
metrics_minheap *args
when 'time'
metrics_time *args
else
raise ArgumentError, command
end
end

def metrics_alloc(*args)
samples = []
METRICS_REPS.times do
print '.' if STDOUT.tty?
r, w = IO.pipe
run '-Xtruffle.metrics.memory_used_on_exit=true', '-J-verbose:gc', *args, {err: w, out: w}, :no_print_cmd
w.close
samples.push memory_allocated(r.read)
r.close
end
puts if STDOUT.tty?
puts "#{human_size(samples.inject(:+)/samples.size)}, max #{human_size(samples.max)}"
end

def memory_allocated(trace)
allocated = 0
trace.lines do |line|
case line
when /(\d+)K->(\d+)K/
before = $1.to_i * 1024
after = $2.to_i * 1024
collected = before - after
allocated += collected
when /^allocated (\d+)$/
allocated += $1.to_i
end
end
allocated
end

def metrics_minheap(*args)
# Why aren't you doing a binary search? The results seem pretty noisy so
# unless you do reps at each level I'm not sure how to make it work
# reliably.
heap = 1
successful = 0
loop do
if successful > 0
print '?' if STDOUT.tty?
else
print '+' if STDOUT.tty?
end
if run("-J-Xmx#{heap}M", *args, {err: '/dev/null', out: '/dev/null'}, :continue_on_failure, :no_print_cmd)
successful += 1
break if successful == METRICS_REPS
else
heap += 1
successful = 0
end
end
puts if STDOUT.tty?
puts "#{heap} MB"
end

def metrics_time(*args)
samples = []
METRICS_REPS.times do
print '.' if STDOUT.tty?
r, w = IO.pipe
start = Time.now
run '-Xtruffle.metrics.time=true', *args, {err: w, out: w}, :no_print_cmd
finish = Time.now
w.close
samples.push get_times(r.read, finish - start)
r.close
end
puts if STDOUT.tty?
samples[0].each_key do |region|
region_samples = samples.map { |s| s[region] }
puts "#{region} #{(region_samples.inject(:+)/samples.size).round(2)} s"
end
end

def get_times(trace, total)
start_times = {}
times = {}
depth = 1
accounted_for = 0
trace.lines do |line|
if line =~ /^([a-z\-]+) (\d+\.\d+)$/
region = $1
time = $2.to_f
if region.start_with? 'before-'
depth += 1
region = (' ' * depth + region['before-'.size..-1])
start_times[region] = time
elsif region.start_with? 'after-'
region = (' ' * depth + region['after-'.size..-1])
depth -= 1
elapsed = time - start_times[region]
times[region] = elapsed
accounted_for += elapsed if depth == 2
end
end
end
times[' jvm'] = total - times[' main']
times['total'] = total
times['unaccounted'] = total - accounted_for
times
end

def human_size(bytes)
if bytes < 1024
"#{bytes} B"
elsif bytes < 1000**2
"#{(bytes/1024.0).round(2)} KB"
elsif bytes < 1000**3
"#{(bytes/1024.0**2).round(2)} MB"
elsif bytes < 1000**4
"#{(bytes/1024.0**3).round(2)} GB"
else
raise ArgumentError, report
"#{(bytes/1024.0**4).round(2)} TB"
end
end

13 changes: 7 additions & 6 deletions truffle/src/main/java/org/jruby/truffle/RubyContext.java
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@
import jnr.posix.POSIXFactory;
import org.jcodings.Encoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.Ruby;
import org.jruby.*;
import org.jruby.ext.ffi.Platform;
import org.jruby.ext.ffi.Platform.OS_TYPE;
import org.jruby.runtime.Visibility;
@@ -144,8 +144,7 @@ public RubyContext(Ruby runtime, TruffleLanguage.Env env) {
compilerOptions = Truffle.getRuntime().createCompilerOptions();

if (!onGraal() && options.GRAAL_WARNING_UNLESS) {
System.err.println("WARNING: JRuby+Truffle is designed to be used with a JVM that has the Graal compiler. " +
"Without the Graal compiler, performance will be drastically reduced. " +
System.err.println("WARNING: This JVM does not have the Graal compiler. JRuby+Truffle's performance without it will be limited. " +
"See https://github.com/jruby/jruby/wiki/Truffle-FAQ#how-do-i-get-jrubytruffle");
}

@@ -202,7 +201,12 @@ public RubyContext(Ruby runtime, TruffleLanguage.Env env) {

coreLibrary = new CoreLibrary(this);
rootLexicalScope = new LexicalScope(null, coreLibrary.getObjectClass());

org.jruby.Main.printTruffleTimeMetric("before-load-nodes");
coreLibrary.initialize();
rubiniusPrimitiveManager = new RubiniusPrimitiveManager();
rubiniusPrimitiveManager.addAnnotatedPrimitives();
org.jruby.Main.printTruffleTimeMetric("after-load-nodes");

featureLoader = new FeatureLoader(this);
traceManager = new TraceManager(this);
@@ -211,9 +215,6 @@ public RubyContext(Ruby runtime, TruffleLanguage.Env env) {
threadManager = new ThreadManager(this);
threadManager.initialize();

rubiniusPrimitiveManager = new RubiniusPrimitiveManager();
rubiniusPrimitiveManager.addAnnotatedPrimitives();

if (options.INSTRUMENTATION_SERVER_PORT != 0) {
instrumentationServerManager = new InstrumentationServerManager(this, options.INSTRUMENTATION_SERVER_PORT);
instrumentationServerManager.start();
6 changes: 2 additions & 4 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -582,7 +582,6 @@ private void addCoreMethods() {
// Bring in core method nodes
CoreMethodNodeManager coreMethodNodeManager = new CoreMethodNodeManager(context, node.getSingletonClassNode());

Main.printTruffleTimeMetric("before-load-truffle-nodes");
coreMethodNodeManager.addCoreMethodNodes(ArrayNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(BasicObjectNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(BindingNodesFactory.getFactories());
@@ -630,7 +629,6 @@ private void addCoreMethods() {
coreMethodNodeManager.addCoreMethodNodes(PsychParserNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(PsychEmitterNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(AtomicReferenceNodesFactory.getFactories());
Main.printTruffleTimeMetric("after-load-truffle-nodes");

coreMethodNodeManager.allMethodInstalled();

@@ -760,7 +758,7 @@ public void initializeAfterMethodsAdded() {
// Load Ruby core

try {
Main.printTruffleTimeMetric("before-load-truffle-core");
Main.printTruffleTimeMetric("before-load-core");

state = State.LOADING_RUBY_CORE;
try {
@@ -769,7 +767,7 @@ public void initializeAfterMethodsAdded() {
throw new RuntimeException(e);
}

Main.printTruffleTimeMetric("after-load-truffle-core");
Main.printTruffleTimeMetric("after-load-core");
} catch (RaiseException e) {
final Object rubyException = e.getRubyException();
BacktraceFormatter.createDefaultFormatter(getContext()).printBacktrace(context, (DynamicObject) rubyException, Layouts.EXCEPTION.getBacktrace((DynamicObject) rubyException));
Original file line number Diff line number Diff line change
@@ -215,8 +215,8 @@ public Object getIndexSymbol(DynamicObject matchData, DynamicObject index, NotPr
@Specialization(guards = "isRubyString(index)")
public Object getIndexString(DynamicObject matchData, DynamicObject index, NotProvided length) {
try {
ByteList value = StringOperations.getByteListReadOnly(index);
final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getUnsafeBytes(), value.getBegin(), value.getBegin() + value.getRealSize(), Layouts.MATCH_DATA.getRegion(matchData));
final Rope value = StringOperations.rope(index);
final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getBytes(), value.getBegin(), value.getBegin() + value.getRealSize(), Layouts.MATCH_DATA.getRegion(matchData));

return getIndex(matchData, i, NotProvided.INSTANCE);
}
@@ -373,7 +373,6 @@ public PreMatchNode(RubyContext context, SourceSection sourceSection) {
taintResultNode = new TaintResultNode(getContext(), getSourceSection());
}

@CompilerDirectives.TruffleBoundary
@Specialization
public Object preMatch(DynamicObject matchData) {
return taintResultNode.maybeTaint(Layouts.MATCH_DATA.getSource(matchData), Layouts.MATCH_DATA.getPre(matchData));
@@ -391,7 +390,6 @@ public PostMatchNode(RubyContext context, SourceSection sourceSection) {
taintResultNode = new TaintResultNode(getContext(), getSourceSection());
}

@CompilerDirectives.TruffleBoundary
@Specialization
public Object postMatch(DynamicObject matchData) {
return taintResultNode.maybeTaint(Layouts.MATCH_DATA.getSource(matchData), Layouts.MATCH_DATA.getPost(matchData));
@@ -420,11 +418,10 @@ public ToSNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public DynamicObject toS(DynamicObject matchData) {
final ByteList bytes = StringOperations.getByteListReadOnly(Layouts.MATCH_DATA.getGlobal(matchData)).dup();
return createString(bytes);
final Rope rope = StringOperations.rope(Layouts.MATCH_DATA.getGlobal(matchData));
return createString(rope);
}
}

@@ -435,7 +432,6 @@ public RegexpNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public DynamicObject regexp(DynamicObject matchData) {
return Layouts.MATCH_DATA.getRegexp(matchData);
@@ -466,7 +462,6 @@ public RubiniusSourceNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public DynamicObject rubiniusSource(DynamicObject matchData) {
return Layouts.MATCH_DATA.getSource(matchData);
Original file line number Diff line number Diff line change
@@ -172,7 +172,6 @@ public static Object matchCommon(RubyContext context, RopeNodes.MakeSubstringNod
}
}

@TruffleBoundary
private static DynamicObject createSubstring(RopeNodes.MakeSubstringNode makeSubstringNode, DynamicObject source, int start, int length) {
assert RubyGuards.isRubyString(source);

@@ -224,8 +223,7 @@ public static Rope shimModifiers(Rope bytes) {
throw new UnsupportedOperationException();
}

// TODO (nirvdrum 25-Jan-16): We probably just want a way to create a Rope from a java.lang.String.
bytes = StringOperations.ropeFromByteList(ByteList.create(bytesString));
bytes = StringOperations.createRope(bytesString, ASCIIEncoding.INSTANCE);
}

return bytes;
@@ -422,21 +420,6 @@ public Object matchGeneric(VirtualFrame frame, DynamicObject regexp, DynamicObje

}

@CoreMethod(names = "escape", onSingleton = true, required = 1)
public abstract static class EscapeNode extends CoreMethodArrayArgumentsNode {

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

@TruffleBoundary
@Specialization(guards = "isRubyString(pattern)")
public DynamicObject escape(DynamicObject pattern) {
return createString(StringOperations.encodeRope(org.jruby.RubyRegexp.quote19(new ByteList(StringOperations.getByteListReadOnly(pattern)), true).toString(), UTF8Encoding.INSTANCE));
}

}

@CoreMethod(names = "hash")
public abstract static class HashNode extends CoreMethodArrayArgumentsNode {

Original file line number Diff line number Diff line change
@@ -51,7 +51,6 @@ public boolean isEmpty() {

public final ByteList getUnsafeByteList() {
if (unsafeByteList == null) {
CompilerDirectives.transferToInterpreter();
unsafeByteList = new ByteList(getBytes(), getEncoding(), false);
}

10 changes: 5 additions & 5 deletions truffle/src/main/java/org/jruby/truffle/core/rope/RopeNodes.java
Original file line number Diff line number Diff line change
@@ -288,12 +288,12 @@ private boolean isSingleByteOptimizable(Rope left, Rope right, ConditionProfile
}

private int depth(Rope left, Rope right) {
final int x = left.depth();
final int y = right.depth();

int maxChildDepth = x - ((x - y) & ((x - y) >> (Integer.SIZE - 1)));
return max(left.depth(), right.depth()) + 1;
}

return maxChildDepth + 1;
private int max(int x, int y) {
// This approach is adapted from http://graphics.stanford.edu/~seander/bithacks.html?1=1#IntegerMinOrMax
return x - ((x - y) & ((x - y) >> (Integer.SIZE - 1)));
}

protected static boolean isShortLeafRope(Rope rope) {
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
import java.nio.charset.Charset;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.ConcurrentHashMap;

import static org.jruby.truffle.core.rope.CodeRange.*;

@@ -37,6 +38,8 @@ public class RopeOperations {
public static final LeafRope EMPTY_US_ASCII_ROPE = create(new byte [] {}, USASCIIEncoding.INSTANCE, CR_7BIT);
public static final LeafRope EMPTY_UTF8_ROPE = create(new byte[] {}, UTF8Encoding.INSTANCE, CR_7BIT);

private static final ConcurrentHashMap<Encoding, Charset> encodingToCharsetMap = new ConcurrentHashMap<>();

public static LeafRope create(byte[] bytes, Encoding encoding, CodeRange codeRange) {
int characterLength = -1;

@@ -89,7 +92,12 @@ public static String decodeRope(Ruby runtime, Rope value) {
return RubyEncoding.decodeUTF8(value.getBytes(), begin, length);
}

Charset charset = runtime.getEncodingService().charsetForEncoding(encoding);
Charset charset = encodingToCharsetMap.get(encoding);

if (charset == null) {
charset = runtime.getEncodingService().charsetForEncoding(encoding);
encodingToCharsetMap.put(encoding, charset);
}

if (charset == null) {
try {
Original file line number Diff line number Diff line change
@@ -45,7 +45,6 @@ public RubiniusPrimitiveConstructor getPrimitive(String name) {
public void addAnnotatedPrimitives() {
final List<NodeFactory<? extends RubyNode>> nodeFactories = new ArrayList<>();

Main.printTruffleTimeMetric("before-load-rubinius-nodes");
nodeFactories.addAll(VMPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(ObjectPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(TimePrimitiveNodesFactory.getFactories());
@@ -68,7 +67,6 @@ public void addAnnotatedPrimitives() {
nodeFactories.addAll(ExceptionPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(ThreadPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(WeakRefPrimitiveNodesFactory.getFactories());
Main.printTruffleTimeMetric("after-load-rubinius-nodes");

// This comes last as a catch-all
nodeFactories.addAll(UndefinedPrimitiveNodesFactory.getFactories());
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ public Encoding checkEncoding(CodeRangeable other) {

@Override
public ByteList getByteList() {
return StringOperations.getByteList(string);
throw new RuntimeException("Replace with read-only call or rope update for String.");
}


Original file line number Diff line number Diff line change
@@ -176,6 +176,7 @@ public static Encoding checkEncoding(RubyContext context, DynamicObject string,
final Encoding encoding = EncodingNodes.CompatibleQueryNode.compatibleEncodingForStrings(string, other);

if (encoding == null) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(context.getCoreLibrary().encodingCompatibilityErrorIncompatible(
rope(string).getEncoding().toString(),
rope(other).getEncoding().toString(),
@@ -215,10 +216,6 @@ public static Rope createRope(String s, Encoding encoding) {
return RopeOperations.create(ByteList.encode(s, "ISO-8859-1"), encoding, CodeRange.CR_UNKNOWN);
}

public static ByteList getByteList(DynamicObject object) {
throw new RuntimeException("Replace with read-only call or rope update for String.");
}

public static ByteList getByteListReadOnly(DynamicObject object) {
return Layouts.STRING.getRope(object).getUnsafeByteList();
}
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ public class Options {
public final boolean BACKTRACES_OMIT_UNUSED = org.jruby.util.cli.Options.TRUFFLE_BACKTRACES_OMIT_UNUSED.load();
public final boolean INCLUDE_CORE_FILE_CALLERS_IN_SET_TRACE_FUNC = org.jruby.util.cli.Options.TRUFFLE_INCLUDE_CORE_FILE_CALLERS_IN_SET_TRACE_FUNC.load();

// Call garph
// Call graph

public final boolean CALL_GRAPH = org.jruby.util.cli.Options.TRUFFLE_CALL_GRAPH.load();
public final String CALL_GRAPH_WRITE = org.jruby.util.cli.Options.TRUFFLE_CALL_GRAPH_WRITE.load();
Original file line number Diff line number Diff line change
@@ -207,7 +207,7 @@
* {@link Layout} annotations are processed by {@link OMProcessor}.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.SOURCE)
public @interface Layout {

String objectTypeSuperclass() default "ObjectType";
Original file line number Diff line number Diff line change
@@ -18,6 +18,6 @@
* @see Layout
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.SOURCE)
public @interface Nullable {
}
Original file line number Diff line number Diff line change
@@ -18,6 +18,6 @@
* @see Layout
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.SOURCE)
public @interface Volatile {
}
Original file line number Diff line number Diff line change
@@ -611,14 +611,14 @@ public void run(PropertyModel property, boolean last) {

if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(" return ((AtomicInteger) %s_PROPERTY.get(object, true)).get();%n", NameUtils.identifierToConstant(property.getName()));
stream.printf(" return ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).get();%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(" return ((AtomicBoolean) %s_PROPERTY.get(object, true)).get();%n", NameUtils.identifierToConstant(property.getName()));
stream.printf(" return ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).get();%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(" return ((AtomicReference<%s>) %s_PROPERTY.get(object, true)).get();%n", property.getType(), NameUtils.identifierToConstant(property.getName()));
stream.printf(" return ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).get();%n", property.getType(), NameUtils.identifierToConstant(property.getName()), layout.getName());
}
} else {
stream.printf(" return (%s) %s_PROPERTY.get(object, true);%n", property.getType(), NameUtils.identifierToConstant(property.getName()));
stream.printf(" return (%s) %s_PROPERTY.get(object, is%s(object));%n", property.getType(), NameUtils.identifierToConstant(property.getName()), layout.getName());
}
}

@@ -675,11 +675,11 @@ public void run(PropertyModel property, boolean last) {
stream.printf(" %s_PROPERTY.setInternal(object, value);%n", NameUtils.identifierToConstant(property.getName()));
} else if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(" ((AtomicInteger) %s_PROPERTY.get(object, true)).set(value);%n", NameUtils.identifierToConstant(property.getName()));
stream.printf(" ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).set(value);%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(" ((AtomicBoolean) %s_PROPERTY.get(object, true)).set(value);%n", NameUtils.identifierToConstant(property.getName()));
stream.printf(" ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).set(value);%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(" ((AtomicReference<%s>) %s_PROPERTY.get(object, true)).set(value);%n", property.getType(), NameUtils.identifierToConstant(property.getName()));
stream.printf(" ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).set(value);%n", property.getType(), NameUtils.identifierToConstant(property.getName()), layout.getName());
}
} else {
stream.printf(" try {%n");
@@ -712,17 +712,17 @@ public void run(PropertyModel property, boolean last) {

if (property.getType().getKind() == TypeKind.INT) {
stream.printf(
" return ((AtomicInteger) %s_PROPERTY.get(object, true)).compareAndSet(expected_value, value);%n",
NameUtils.identifierToConstant(property.getName()));
" return ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).compareAndSet(expected_value, value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(
" return ((AtomicBoolean) %s_PROPERTY.get(object, true)).compareAndSet(expected_value, value);%n",
NameUtils.identifierToConstant(property.getName()));
" return ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).compareAndSet(expected_value, value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(
" return ((AtomicReference<%s>) %s_PROPERTY.get(object, true)).compareAndSet(expected_value, value);%n",
" return ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).compareAndSet(expected_value, value);%n",
property.getType(),
NameUtils.identifierToConstant(property.getName()));
NameUtils.identifierToConstant(property.getName()), layout.getName());
}

stream.println(" }");
@@ -747,17 +747,17 @@ public void run(PropertyModel property, boolean last) {

if (property.getType().getKind() == TypeKind.INT) {
stream.printf(
" return ((AtomicInteger) %s_PROPERTY.get(object, true)).getAndSet(value);%n",
NameUtils.identifierToConstant(property.getName()));
" return ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).getAndSet(value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(
" return ((AtomicBoolean) %s_PROPERTY.get(object, true)).getAndSet(value);%n",
NameUtils.identifierToConstant(property.getName()));
" return ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).getAndSet(value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(
" return ((AtomicReference<%s>) %s_PROPERTY.get(object, true)).getAndSet(value);%n",
" return ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).getAndSet(value);%n",
property.getType(),
NameUtils.identifierToConstant(property.getName()));
NameUtils.identifierToConstant(property.getName()), layout.getName());
}

stream.println(" }");

0 comments on commit 6cf692b

Please sign in to comment.