Skip to content

Commit

Permalink
Showing 51 changed files with 495 additions and 222 deletions.
10 changes: 8 additions & 2 deletions bin/jruby.bash
Original file line number Diff line number Diff line change
@@ -243,9 +243,10 @@ do
# Pass -X... and -X? search options through
-X*\.\.\.|-X*\?)
ruby_args=("${ruby_args[@]}" "$1") ;;
-Xclassic)
unset USING_TRUFFLE
;;
-X+T)
JRUBY_CP="$JRUBY_CP$CP_DELIMITER$JRUBY_HOME/lib/jruby-truffle.jar"
ruby_args=("${ruby_args[@]}" "-X+T")
USING_TRUFFLE="true"
;;
# Match -Xa.b.c=d to translate to -Da.b.c=d as a java option
@@ -315,6 +316,11 @@ do
shift
done

if [[ "$USING_TRUFFLE" != "" ]]; then
JRUBY_CP="$JRUBY_CP$CP_DELIMITER$JRUBY_HOME/lib/jruby-truffle.jar"
ruby_args=("${ruby_args[@]}" "-X+T")
fi

# Force file.encoding to UTF-8 when on Mac, since Apple JDK defaults to MacRoman (JRUBY-3576)
if [[ $darwin && -z "$JAVA_ENCODING" ]]; then
java_args=("${java_args[@]}" "-Dfile.encoding=UTF-8")
6 changes: 4 additions & 2 deletions bin/jruby.sh
Original file line number Diff line number Diff line change
@@ -197,8 +197,10 @@ do
-X*\.\.\.|-X*\?)
ruby_args="${ruby_args} $1" ;;
-X+T)
JRUBY_CP="$JRUBY_CP$CP_DELIMITER$JRUBY_HOME/lib/jruby-truffle.jar"
ruby_args="${ruby_args} -X+T"
echo "error: -X+T isn't supported in the shell launcher"
exit 1
;;
-Xclassic)
;;
# Match -Xa.b.c=d to translate to -Da.b.c=d as a java option
-X*)
8 changes: 4 additions & 4 deletions ci.hocon
Original file line number Diff line number Diff line change
@@ -81,7 +81,7 @@ jruby-noindy-metrics: {
environment: {
GUEST_VM: jruby,
GUEST_VM_CONFIG: noindy,
JRUBY_OPTS: "-X-T -Xcompile.invokedynamic=false",
JRUBY_OPTS: "-Xclassic -Xcompile.invokedynamic=false",
MX_BENCHMARK_OPTS: --no-graal
}
}
@@ -90,7 +90,7 @@ jruby-noindy-benchmark: {
environment: {
GUEST_VM: jruby,
GUEST_VM_CONFIG: noindy,
JRUBY_OPTS: "-X-T -X+C -Xcompile.invokedynamic=false",
JRUBY_OPTS: "-Xclassic -X+C -Xcompile.invokedynamic=false",
MX_BENCHMARK_OPTS: --no-graal
}
}
@@ -99,7 +99,7 @@ jruby-indy-metrics: {
environment: {
GUEST_VM: jruby,
GUEST_VM_CONFIG: indy,
JRUBY_OPTS: "-X-T -Xcompile.invokedynamic=true",
JRUBY_OPTS: "-Xclassic -Xcompile.invokedynamic=true",
MX_BENCHMARK_OPTS: --no-graal
}
}
@@ -108,7 +108,7 @@ jruby-indy-benchmark: {
environment: {
GUEST_VM: jruby,
GUEST_VM_CONFIG: indy,
JRUBY_OPTS: "-X-T -X+C -Xcompile.invokedynamic=true",
JRUBY_OPTS: "-Xclassic -X+C -Xcompile.invokedynamic=true",
MX_BENCHMARK_OPTS: --no-graal
}
}
2 changes: 0 additions & 2 deletions core/src/main/java/org/jruby/compiler/JITCompiler.java
Original file line number Diff line number Diff line change
@@ -59,9 +59,7 @@
import java.lang.invoke.MethodType;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
6 changes: 2 additions & 4 deletions core/src/main/java/org/jruby/util/cli/ArgumentProcessor.java
Original file line number Diff line number Diff line change
@@ -388,10 +388,8 @@ private void processArgument() {
config.setCompileMode(RubyInstanceConfig.CompileMode.OFF);
} else if (extendedOption.equals("+C") || extendedOption.equals("+CIR")) {
config.setCompileMode(RubyInstanceConfig.CompileMode.FORCE);
} else if (extendedOption.equals("-T")) {
config.setCompileMode(RubyInstanceConfig.CompileMode.OFF);
Options.COMPILE_MODE.unforce();
config.setDisableGems(false);
} else if (extendedOption.equals("classic")) {
throw new MainExitException(0, "jruby: the -Xclassic option should have been handled in the launcher");
} else if (extendedOption.equals("+T")) {
Options.PARSER_WARN_GROUPED_EXPRESSIONS.force(Boolean.FALSE.toString());
config.setCompileMode(RubyInstanceConfig.CompileMode.TRUFFLE);
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/util/cli/Options.java
Original file line number Diff line number Diff line change
@@ -266,6 +266,7 @@ public class Options {
public static final Option<Integer> TRUFFLE_EVAL_CACHE = integer(TRUFFLE, "truffle.eval.cache", TRUFFLE_DEFAULT_CACHE.load(), "eval cache size.");
public static final Option<Integer> TRUFFLE_CLASS_CACHE = integer(TRUFFLE, "truffle.class.cache", TRUFFLE_DEFAULT_CACHE.load(), ".class and .metaclass cache size.");
public static final Option<Integer> TRUFFLE_ENCODING_COMPATIBLE_QUERY_CACHE = integer(TRUFFLE, "truffle.encoding_compatible_query.cache", TRUFFLE_DEFAULT_CACHE.load(), "Encoding.compatible? cache size.");
public static final Option<Integer> TRUFFLE_ENCODING_LOADED_CLASSES_CACHE = integer(TRUFFLE, "truffle.encoding_loaded_classes.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size of encoding operations based on anticipated number of total active encodings.");
public static final Option<Integer> TRUFFLE_THREAD_CACHE = integer(TRUFFLE, "truffle.thread.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size of operations that depend on a particular thread.");
public static final Option<Integer> TRUFFLE_ROPE_CLASS_CACHE = integer(TRUFFLE, "truffle.rope_class.cache", 6, "Cache size for rope operations that depend on a concrete rope implementation to avoid virtual calls.");
public static final Option<Integer> TRUFFLE_INTEROP_CONVERT_CACHE = integer(TRUFFLE, "truffle.interop.convert.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size for converting values for interop.");
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/util/cli/OutputStrings.java
Original file line number Diff line number Diff line change
@@ -88,6 +88,7 @@ public static String getExtendedHelp() {
.append(" -X+CIR force compilation and use IR runtime\n")
.append(" -X+JIR JIT compilation and use IR runtime\n")
.append(" -X+T use Truffle\n")
.append(" -Xclassic don't use Truffle, reversing the -X+T option\n")
.append(" -Xsubstring? list options that contain substring in their name\n")
.append(" -Xprefix... list options that are prefixed wtih prefix\n");

35 changes: 23 additions & 12 deletions core/src/main/ruby/jruby/java/core_ext/kernel.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
# frozen-literal-string: true

# Create convenience methods for top-level java packages so we do not need to prefix
# with Java::com. We undef these methods within Package in case we run into 'com.foo.com'.
# Convenience methods for top-level packages without the need to prefix e.g. `Java::java.util.ArrayList`.
# @note These methods are undef-ed within Java package stubs (in case of *com.foo.com*).
module Kernel
# Java package short-cut method.
# @example
# java.lang.System
def java
JavaUtilities.get_package_module_dot_format('java')
JavaUtilities.get_package_module_dot_format('java') # stub
end

# Java package short-cut method.
# @example
# javax.swing.SwingUtilities
def javax
JavaUtilities.get_package_module_dot_format('javax')
JavaUtilities.get_package_module_dot_format('javax') # stub
end

# Java package short-cut method.
# @example
# javafx.application.Platform
def javafx
JavaUtilities.get_package_module_dot_format('javafx')
JavaUtilities.get_package_module_dot_format('javafx') # stub
end

# Java package short-cut method.
# @example
# com.google.common.base.Strings
def com
JavaUtilities.get_package_module_dot_format('com')
JavaUtilities.get_package_module_dot_format('com') # stub
end

# Java package short-cut method.
# @example
# org.json.JSONArray
def org
JavaUtilities.get_package_module_dot_format('org')
JavaUtilities.get_package_module_dot_format('org') # stub
end
end
end if false
42 changes: 29 additions & 13 deletions lib/pom.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
MORE_QUIET = ENV['JRUBY_BUILD_MORE_QUIET']

if MORE_QUIET
class Gem::Installer
def say(message)
if message != spec.post_install_message || !MORE_QUIET
super
end
end
end
end

def log(message=nil)
puts message unless MORE_QUIET
end

class ImportedGem
attr_reader :name, :version, :default_spec

@@ -83,7 +99,7 @@ def initialize( name, version, default_spec = true )
execute :install_gems, :'initialize' do |ctx|
require 'fileutils'

puts "using jruby #{JRUBY_VERSION}"
log "using jruby #{JRUBY_VERSION}"

target = ctx.project.build.directory.to_pathname
gem_home = File.join( target, 'rubygems' )
@@ -117,14 +133,14 @@ def initialize( name, version, default_spec = true )
require 'rubygems/installer'
require 'rubygems/package'

puts 'install gems unless already installed'
log 'install gems unless already installed'
ENV_JAVA['jars.skip'] = 'true'
ctx.project.artifacts.select do |a|
a.group_id == 'rubygems' || a.group_id == 'org.jruby.gems'
end.each do |a|
ghome = default_gemnames.member?( a.artifact_id ) ? gem_home : jruby_gems
if Dir[ File.join( ghome, 'cache', File.basename( a.file.to_pathname ).sub( /.gem/, '*.gem' ) ) ].empty?
puts a.file.to_pathname
log a.file.to_pathname
installer = Gem::Installer.new( a.file.to_pathname,
:wrappers => true,
:ignore_dependencies => true,
@@ -141,19 +157,19 @@ def installer.ensure_required_ruby_version_met; end
# install the gem unless already installed
if Dir[ File.join( default_specs, "#{g.name}-#{version}*.gemspec" ) ].empty?

puts
puts "--- gem #{g.name}-#{version} ---"
log
log "--- gem #{g.name}-#{version} ---"

# copy the gem content to stdlib

puts "copy gem content to #{stdlib_dir}"
log "copy gem content to #{stdlib_dir}"
# assume default require_path
require_base = File.join( gems, "#{g.name}-#{version}*", 'lib' )
require_files = File.join( require_base, '*' )

# copy in new ones and mark writable for future updates (e.g. minitest)
stdlib_locs = Dir[ require_files ].map do |f|
puts " copying: #{f} to #{stdlib_dir}" if $VERBOSE
log " copying: #{f} to #{stdlib_dir}" if $VERBOSE
FileUtils.cp_r( f, stdlib_dir )

stdlib_loc = f.sub( File.dirname(f), stdlib_dir )
@@ -164,7 +180,7 @@ def installer.ensure_required_ruby_version_met; end
# fix permissions on copied files
stdlib_locs.each do |f|
next if File.writable? f
puts " fixing permissions: #{f}" if $VERBOSE
log " fixing permissions: #{f}" if $VERBOSE
# TODO: better way to just set it writable without changing all modes?
FileUtils.chmod_R(0644, f)
end
@@ -173,7 +189,7 @@ def installer.ensure_required_ruby_version_met; end
bin = File.join( gems, "#{g.name}-#{version}", 'bin' )
if File.exists? bin
Dir[ File.join( bin, '*' ) ].each do |f|
puts "copy to bin: #{File.basename( f )}"
log "copy to bin: #{File.basename( f )}"
target = File.join( bin_stubs, f.sub( /#{gems}/, '' ) )
FileUtils.mkdir_p( File.dirname( target ) )
FileUtils.cp_r( f, target )
@@ -189,7 +205,7 @@ def installer.ensure_required_ruby_version_met; end
end

specname = File.basename( specfile )
puts "copy to specifications/default: #{specname}"
log "copy to specifications/default: #{specname}"

spec = Gem::Package.new( Dir[ File.join( cache, "#{g.name}-#{version}*.gem" ) ].first ).spec
File.open( File.join( default_specs, specname ), 'w' ) do |f|
@@ -217,7 +233,7 @@ def installer.ensure_required_ruby_version_met; end
execute( 'fix shebang on gem bin files and add *.bat files',
'generate-resources' ) do |ctx|

puts 'fix the gem stub files'
log 'fix the gem stub files'
jruby_home = ctx.project.basedir.to_pathname + '/../'
bindir = File.join( jruby_home, 'lib', 'ruby', 'gems', 'shared', 'bin' )
Dir[ File.join( bindir, '*' ) ].each do |f|
@@ -227,7 +243,7 @@ def installer.ensure_required_ruby_version_met; end
File.open( f, "w" ) { |file| file.print( new_content ) }
end

puts 'generating missing .bat files'
log 'generating missing .bat files'
Dir[File.join( jruby_home, 'bin', '*' )].each do |fn|
next unless File.file?(fn)
next if fn =~ /.bat$/
@@ -236,7 +252,7 @@ def installer.ensure_required_ruby_version_met; end
line = io.readline rescue ""
line =~ /^#!.*ruby/
end
puts " generating #{File.basename(fn)}.bat" if $VERBOSE
log " generating #{File.basename(fn)}.bat" if $VERBOSE
File.open("#{fn}.bat", "wb") do |f|
f.print "@ECHO OFF\r\n"
f.print "@\"%~dp0jruby.exe\" -S #{File.basename(fn)} %*\r\n"
16 changes: 13 additions & 3 deletions mx.jruby/mx_jruby.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 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

import os
import subprocess
import shutil
@@ -97,16 +105,18 @@ def build(self):
open(os.path.join(rubyDir, 'VERSION'), 'w').write('graal-vm\n')

# Build jruby-truffle

env = {'JRUBY_BUILD_MORE_QUIET': 'true'}

mx.run_maven(['-q', '--version', maven_repo_arg], nonZeroIsFatal=False, cwd=rubyDir)
mx.run_maven(['-q', '--version', maven_repo_arg], nonZeroIsFatal=False, cwd=rubyDir, env=env)

mx.log('Building without tests')

mx.run_maven(['-q', '-DskipTests', maven_version_arg, maven_repo_arg], cwd=rubyDir)
mx.run_maven(['-q', '-DskipTests', maven_version_arg, maven_repo_arg], cwd=rubyDir, env=env)

mx.log('Building complete version')

mx.run_maven(['-q', '-Pcomplete', '-DskipTests', maven_version_arg, maven_repo_arg], cwd=rubyDir)
mx.run_maven(['-q', '-Pcomplete', '-DskipTests', maven_version_arg, maven_repo_arg], cwd=rubyDir, env=env)
mx.run(['zip', '-d', 'maven/jruby-complete/target/jruby-complete-graal-vm.jar', 'META-INF/jruby.home/lib/*'], cwd=rubyDir)
mx.run(['bin/jruby', 'bin/gem', 'install', 'bundler', '-v', '1.10.6'], cwd=rubyDir)
mx.log('...finished build of {}'.format(self.subject))
8 changes: 8 additions & 0 deletions mx.jruby/suite.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 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

suite = {
"mxversion": "5.6.6",
"name": "jrubytruffle",
7 changes: 7 additions & 0 deletions samples/truffle/interop/weather/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```
$ git clone https://github.com/lucasocon/openweather.git
RUBYOPT='-I samples/truffle/interop/weather/openweather/lib -I samples/truffle/interop/weather' graalvm/bin/js samples/truffle/interop/weather/weather.js
```

The demo hangs after printing the temperature, as some Ruby service threads
get stuck and aren't shutting down properly.
5 changes: 5 additions & 0 deletions samples/truffle/interop/weather/weather.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Interop.eval('application/x-ruby', 'require "weather"');

temperature_in_city = Interop.import('temperature_in_city')

console.log('Temperature in New York now: ' + temperature_in_city.call('New York') + '℃');
15 changes: 15 additions & 0 deletions samples/truffle/interop/weather/weather.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'openweather2'

Openweather2.configure do |config|
# This is the endpoint and API key from the tests in the Openweather2 gem
config.endpoint = 'http://api.openweathermap.org/data/2.5/weather'
config.apikey = 'dd7073d18e3085d0300b6678615d904d'
end

def temperature_in_city(name)
name = Truffle::Interop.from_java_string(name)
weather = Openweather2.get_weather(city: name, units: 'metric')
weather.temperature
end

Truffle::Interop.export_method :temperature_in_city
1 change: 1 addition & 0 deletions spec/truffle/tags/core/argf/readline_tags.txt
Original file line number Diff line number Diff line change
@@ -2,3 +2,4 @@ fails:ARGF.readline sets $_ global variable with each line read
fails:ARGF.readline modifies the files when in place edit mode is on
fails:ARGF.readline modifies and backups two files when in place edit mode is on
slow:ARGF.readline reads all lines of stdin
fails:ARGF.readline reads all lines of stdin
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/kernel/sprintf_tags.txt
Original file line number Diff line number Diff line change
@@ -3,8 +3,6 @@ fails:Kernel#sprintf passes some tests for negative %x
fails:Kernel#sprintf passes some tests for negative %u
fails:Kernel#sprintf passes some tests for positive %u
fails:Kernel#sprintf passes some tests for positive %d
fails:Kernel#sprintf passes some tests for positive %f
fails:Kernel#sprintf passes some tests for negative %f
fails:Kernel#sprintf passes kstephens's tests
fails:Kernel#sprintf returns a String in the same encoding as the format String if compatible
fails:Kernel#sprintf returns a String in the argument encoding if format encoding is more restrictive
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/string/modulo_tags.txt
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ fails:String#% replaces trailing absolute argument specifier without type with p
fails:String#% raises an ArgumentError when given invalid argument specifiers
fails:String#% raises an ArgumentError when multiple positional argument tokens are given for one format specifier
fails:String#% respects positional arguments and precision tokens given for one format specifier
fails:String#% allows more than one digit of position
fails:String#% raises an ArgumentError when multiple width star tokens are given for one format specifier
fails:String#% raises an ArgumentError when a width star token is seen after a width token
fails:String#% raises an ArgumentError when multiple precision tokens are given
@@ -25,9 +24,7 @@ fails:String#% raises a TypeError if #to_ary does not return an Array
fails:String#% tries to convert the argument to Array by calling #to_ary
fails:String#% doesn't return subclass instances when called on a subclass
fails:String#% always taints the result when the format string is tainted
fails:String#% supports binary formats using %b for positive numbers
fails:String#% supports binary formats using %b for negative numbers
fails:String#% supports binary formats using %B with same behaviour as %b except for using 0B instead of 0b for #
fails:String#% supports character formats using %c
fails:String#% supports single character strings as argument for %c
fails:String#% raises an exception for multiple character strings as argument for %c
@@ -57,8 +54,6 @@ fails:String#% supports hex formats using %x for positive numbers
fails:String#% supports hex formats using %x for negative numbers
fails:String#% supports hex formats using %X for positive numbers
fails:String#% supports hex formats using %X for negative numbers
fails:String#% formats zero without prefix using %#x
fails:String#% formats zero without prefix using %#X
fails:String#% tries to convert the passed argument to an Array using #to_ary
fails:String#% behaves as if calling Kernel#Float for %e arguments, when the passed argument does not respond to #to_ary
fails:String#% behaves as if calling Kernel#Float for %e arguments, when the passed argument is hexadecimal string
13 changes: 13 additions & 0 deletions test/truffle/compiler/pe/core/encoding_pe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 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

example "Encoding::US_ASCII.ascii_compatible?", true
example "Encoding::UTF_16BE.ascii_compatible?", false

example "Encoding::ISO_2022_JP.dummy?", true
example "Encoding::UTF_8.dummy?", false
1 change: 1 addition & 0 deletions test/truffle/compiler/pe/pe.rb
Original file line number Diff line number Diff line change
@@ -86,6 +86,7 @@ def counter(example)
require_relative 'core/block_given_pe.rb'
require_relative 'core/string_pe.rb'
require_relative 'core/class_pe'
require_relative 'core/encoding_pe'
require_relative 'interop/interop_pe'
require_relative 'macro/pushing_pixels_pe.rb'

17 changes: 12 additions & 5 deletions tool/jt.rb
Original file line number Diff line number Diff line change
@@ -292,7 +292,13 @@ def sh(*args)
end

def mvn(*args)
sh './mvnw', *(['-q'] + args)
if args.first.is_a? Hash
options = [args.shift]
else
options = []
end

sh *options, './mvnw', *(['-q'] + args)
end

def maven_options(*options)
@@ -367,7 +373,7 @@ def help
puts 'jt tag all spec/ruby/language tag all specs in this file, without running them'
puts 'jt untag spec/ruby/language untag passing specs in this directory'
puts 'jt untag spec/ruby/language/while_spec.rb untag passing specs in this file'
puts 'jt metrics alloc [--json] ... how much memory is allocated running a program (use -X-T to test normal JRuby on this metric and others)'
puts 'jt metrics alloc [--json] ... how much memory is allocated running a program (use -Xclassic 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 tarball build the and test the distribution tarball'
@@ -408,11 +414,12 @@ def bootstrap(*options)
def build(*options)
maven_options, other_options = maven_options(*options)
project = other_options.first
env = {'JRUBY_BUILD_MORE_QUIET' => 'true'}
case project
when 'truffle'
mvn *maven_options, '-pl', 'truffle', 'package'
mvn env, *maven_options, '-pl', 'truffle', 'package'
when nil
mvn *maven_options, 'package'
mvn env, *maven_options, 'package'
else
raise ArgumentError, project
end
@@ -441,7 +448,7 @@ def run(*args)
'-Xtruffle.graal.warn_unless=false'
]

if ENV['JRUBY_OPTS'] && ENV['JRUBY_OPTS'].include?('-X-T')
if ENV['JRUBY_OPTS'] && ENV['JRUBY_OPTS'].include?('-Xclassic')
jruby_args.delete '-X+T'
end

Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ MINUS : '-' ;
STAR : '*' ;
DOLLAR : '$' ;
DOT : '.' ;
HASH : '#' ;
CURLY_KEY : '{' .*? '}' -> mode(DEFAULT_MODE) ;
TYPE : [bBdiouxXeEfgGaAcps] -> mode(DEFAULT_MODE) ;
ESCAPED : '%' -> mode(DEFAULT_MODE) ;
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ flag : SPACE
| PLUS
| MINUS
| STAR
| NUMBER DOLLAR ;
| HASH
| argumentIndex=NUMBER DOLLAR ;

literal : LITERAL ;
6 changes: 6 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/RubyContext.java
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
import org.jruby.Ruby;
import org.jruby.truffle.builtins.PrimitiveManager;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.encoding.EncodingManager;
import org.jruby.truffle.core.exception.CoreExceptions;
import org.jruby.truffle.core.kernel.AtExitManager;
import org.jruby.truffle.core.kernel.TraceManager;
@@ -80,6 +81,7 @@ public class RubyContext extends ExecutionContext {
private final CoreStrings coreStrings = new CoreStrings(this);
private final FrozenStrings frozenStrings = new FrozenStrings(this);
private final CoreExceptions coreExceptions = new CoreExceptions(this);
private final EncodingManager encodingManager = new EncodingManager(this);

private final CompilerOptions compilerOptions = Truffle.getRuntime().createCompilerOptions();

@@ -351,4 +353,8 @@ public CoreExceptions getCoreExceptions() {
return coreExceptions;
}

public EncodingManager getEncodingManager() {
return encodingManager;
}

}
11 changes: 4 additions & 7 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -42,7 +42,6 @@
import org.jruby.truffle.core.bool.TrueClassNodesFactory;
import org.jruby.truffle.core.dir.DirNodesFactory;
import org.jruby.truffle.core.encoding.EncodingConverterNodesFactory;
import org.jruby.truffle.core.encoding.EncodingNodes;
import org.jruby.truffle.core.encoding.EncodingNodesFactory;
import org.jruby.truffle.core.exception.ExceptionNodesFactory;
import org.jruby.truffle.core.fiber.FiberNodesFactory;
@@ -1081,26 +1080,24 @@ public void initializeEncodingConstants() {
getContext().getJRubyRuntime().getEncodingService().defineEncodings(new EncodingService.EncodingDefinitionVisitor() {
@Override
public void defineEncoding(EncodingDB.Entry encodingEntry, byte[] name, int p, int end) {
DynamicObject re = EncodingNodes.newEncoding(encodingClass, null, name, p, end, encodingEntry.isDummy());
EncodingNodes.storeEncoding(encodingEntry.getIndex(), re);
context.getEncodingManager().defineEncoding(encodingClass, encodingEntry, name, p, end);
}

@Override
public void defineConstant(int encodingListIndex, String constName) {
Layouts.MODULE.getFields(encodingClass).setConstant(context, node, constName, EncodingNodes.getEncoding(encodingListIndex));
Layouts.MODULE.getFields(encodingClass).setConstant(context, node, constName, context.getEncodingManager().getRubyEncoding(encodingListIndex));
}
});

getContext().getJRubyRuntime().getEncodingService().defineAliases(new EncodingService.EncodingAliasVisitor() {
@Override
public void defineAlias(int encodingListIndex, String constName) {
DynamicObject re = EncodingNodes.getEncoding(encodingListIndex);
EncodingNodes.storeAlias(constName, re);
context.getEncodingManager().defineAlias(encodingListIndex, constName);
}

@Override
public void defineConstant(int encodingListIndex, String constName) {
Layouts.MODULE.getFields(encodingClass).setConstant(context, node, constName, EncodingNodes.getEncoding(encodingListIndex));
Layouts.MODULE.getFields(encodingClass).setConstant(context, node, constName, context.getEncodingManager().getRubyEncoding(encodingListIndex));
}
});
}
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ public int spawn(DynamicObject command,
Collection<SpawnFileAction> fileActions = parseOptions(options);

final long longPid = call(
StringOperations.getString(getContext(), command),
StringOperations.getString(command),
toStringArray(arguments),
toStringArray(environmentVariables),
fileActions);
@@ -70,7 +70,7 @@ private String[] toStringArray(DynamicObject rubyStrings) {

for (int i = 0; i < size; i++) {
assert Layouts.STRING.isString(unconvertedStrings[i]);
strings[i] = StringOperations.getString(getContext(), (DynamicObject) unconvertedStrings[i]);
strings[i] = StringOperations.getString((DynamicObject) unconvertedStrings[i]);
}

return strings;
@@ -111,7 +111,7 @@ private Collection<SpawnFileAction> parseOptions(DynamicObject options) {
final Object[] store = ArrayOperations.toObjectArray(array);
for (int i = 0; i < size; i += 4) {
int fd = (int) store[i];
String path = StringOperations.getString(getContext(), (DynamicObject) store[i + 1]);
String path = StringOperations.getString((DynamicObject) store[i + 1]);
int flags = (int) store[i + 2];
int perms = (int) store[i + 3];
actions.add(SpawnFileAction.open(path, fd, flags, perms));
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ String stringCached(DynamicObject value,

@Specialization(guards = "isRubyString(value)", contains = "stringCached")
public String stringUncached(DynamicObject value) {
return StringOperations.getString(getContext(), value);
return StringOperations.getString(value);
}

@Specialization(guards = { "symbol == cachedSymbol", "isRubySymbol(cachedSymbol)" }, limit = "getLimit()")
@@ -92,7 +92,7 @@ public String coerceObjectToStr(VirtualFrame frame, Object object,
}

if (RubyGuards.isRubyString(coerced)) {
return StringOperations.getString(getContext(), (DynamicObject) coerced);
return StringOperations.getString((DynamicObject) coerced);
} else {
errorProfile.enter();
throw new RaiseException(coreExceptions().typeErrorBadCoercion(object, "String", "to_str", coerced, this));
Original file line number Diff line number Diff line change
@@ -129,7 +129,8 @@ private IRubyObject toJRuby(Object object) {
if (RubyGuards.isRubyString(object)) {
return getContext().getJRubyRuntime().newString(RopeOperations.toByteListCopy(StringOperations.rope((DynamicObject) object)));
} else if (RubyGuards.isRubyEncoding(object)) {
return getContext().getJRubyRuntime().getEncodingService().rubyEncodingFromObject(getContext().getJRubyRuntime().newString(Layouts.ENCODING.getName((DynamicObject) object)));
final Rope rope = StringOperations.rope(Layouts.ENCODING.getName((DynamicObject) object));
return getContext().getJRubyRuntime().getEncodingService().rubyEncodingFromObject(getContext().getJRubyRuntime().newString(RopeOperations.toByteListCopy(rope)));
} else {
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@
import com.oracle.truffle.api.object.dsl.Nullable;
import org.jcodings.Encoding;
import org.jruby.truffle.core.basicobject.BasicObjectLayout;
import org.jruby.util.ByteList;

@Layout
public interface EncodingLayout extends BasicObjectLayout {
@@ -25,7 +24,7 @@ DynamicObjectFactory createEncodingShape(DynamicObject logicalClass,

DynamicObject createEncoding(DynamicObjectFactory factory,
@Nullable Encoding encoding,
ByteList name,
DynamicObject name,
boolean dummy);

boolean isEncoding(DynamicObject object);
@@ -34,7 +33,7 @@ DynamicObject createEncoding(DynamicObjectFactory factory,
Encoding getEncoding(DynamicObject object);
void setEncoding(DynamicObject object, Encoding value);

ByteList getName(DynamicObject object);
DynamicObject getName(DynamicObject object);

boolean getDummy(DynamicObject object);

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2014, 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.encoding;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.object.DynamicObject;
import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.specific.ISO8859_16Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.util.ByteList;
import org.jruby.util.encoding.ISO_8859_16;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class EncodingManager {

private final DynamicObject[] ENCODING_LIST_BY_ENCODING_LIST_INDEX = new DynamicObject[EncodingDB.getEncodings().size()];
private final DynamicObject[] ENCODING_LIST_BY_ENCODING_INDEX = new DynamicObject[EncodingDB.getEncodings().size()];
private final Map<String, DynamicObject> LOOKUP = new HashMap<>();

private final RubyContext context;

public EncodingManager(RubyContext context) {
this.context = context;
}

@TruffleBoundary
public static DynamicObject newRubyEncoding(RubyContext context, DynamicObject encodingClass, Encoding encoding, byte[] name, int p, int end, boolean dummy) {
// TODO (nirvdrum 21-Jun-16): We probably don't need to create a ByteList and two Ropes. Without any guarantees on the code range of the encoding name, however, we must be conservative.
final Rope rope = StringOperations.ropeFromByteList(new ByteList(name, p, end, USASCIIEncoding.INSTANCE, false));
final Rope cachedRope = context.getRopeTable().getRope(rope.getBytes(), rope.getEncoding(), rope.getCodeRange());
final DynamicObject string = context.getFrozenStrings().getFrozenString(cachedRope);

return Layouts.ENCODING.createEncoding(Layouts.CLASS.getInstanceFactory(encodingClass), encoding, string, dummy);
}

public DynamicObject[] getUnsafeEncodingList() {
return ENCODING_LIST_BY_ENCODING_LIST_INDEX;
}

public DynamicObject getRubyEncoding(Encoding encoding) {
DynamicObject rubyEncoding = ENCODING_LIST_BY_ENCODING_INDEX[encoding.getIndex()];

if (rubyEncoding == null) {
// Bounded by the number of encodings
CompilerDirectives.transferToInterpreterAndInvalidate();

rubyEncoding = LOOKUP.get(new String(encoding.getName(), StandardCharsets.UTF_8).toLowerCase(Locale.ENGLISH));
ENCODING_LIST_BY_ENCODING_INDEX[encoding.getIndex()] = rubyEncoding;
}

return rubyEncoding;
}

@TruffleBoundary
public DynamicObject getRubyEncoding(String name) {
return LOOKUP.get(name.toLowerCase(Locale.ENGLISH));
}

@TruffleBoundary
public DynamicObject getRubyEncoding(int encodingListIndex) {
return ENCODING_LIST_BY_ENCODING_LIST_INDEX[encodingListIndex];
}

@TruffleBoundary
public void defineEncoding(DynamicObject encodingClass, EncodingDB.Entry encodingEntry, byte[] name, int p, int end) {
final DynamicObject rubyEncoding = newRubyEncoding(context, encodingClass, null, name, p, end, encodingEntry.isDummy());

ENCODING_LIST_BY_ENCODING_LIST_INDEX[encodingEntry.getIndex()] = rubyEncoding;
LOOKUP.put(Layouts.ENCODING.getName(rubyEncoding).toString().toLowerCase(Locale.ENGLISH), rubyEncoding);
}

@TruffleBoundary
public void defineAlias(int encodingListIndex, String name) {
final DynamicObject rubyEncoding = getRubyEncoding(encodingListIndex);

LOOKUP.put(name.toLowerCase(Locale.ENGLISH), rubyEncoding);
}

@TruffleBoundary
public Encoding getLocaleEncoding() {
return context.getJRubyRuntime().getEncodingService().getLocaleEncoding();
}

@TruffleBoundary
public static Charset charsetForEncoding(Encoding encoding) {
final String encodingName = encoding.toString();

if (encodingName.equals("ASCII-8BIT")) {
return Charset.forName("ISO-8859-1");
}

if (encoding == ISO8859_16Encoding.INSTANCE) {
return ISO_8859_16.INSTANCE;
}

try {
return Charset.forName(encodingName);
} catch (UnsupportedCharsetException uce) {
throw new UnsupportedOperationException("no java.nio.charset.Charset found for encoding `" + encoding.toString() + "'", uce);
}
}

}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -18,7 +18,8 @@
import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jruby.truffle.Layouts;
import org.jruby.util.ByteList;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.string.StringOperations;

public abstract class EncodingOperations {

@@ -29,7 +30,7 @@ public static Encoding getEncoding(DynamicObject rubyEncoding) {
// Bounded by the number of encodings
CompilerDirectives.transferToInterpreterAndInvalidate();

final ByteList name = Layouts.ENCODING.getName(rubyEncoding);
final Rope name = StringOperations.rope(Layouts.ENCODING.getName(rubyEncoding));
encoding = loadEncoding(name);
Layouts.ENCODING.setEncoding(rubyEncoding, encoding);
}
@@ -38,22 +39,22 @@ public static Encoding getEncoding(DynamicObject rubyEncoding) {
}

@TruffleBoundary
private static EncodingDB.Entry findEncodingEntry(ByteList bytes) {
return EncodingDB.getEncodings().get(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getBegin() + bytes.getRealSize());
private static EncodingDB.Entry findEncodingEntry(Rope name) {
return EncodingDB.getEncodings().get(name.getBytes(), 0, name.byteLength());
}

@TruffleBoundary
private static EncodingDB.Entry findAliasEntry(ByteList bytes) {
return EncodingDB.getAliases().get(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getBegin() + bytes.getRealSize());
private static EncodingDB.Entry findAliasEntry(Rope name) {
return EncodingDB.getAliases().get(name.getBytes(), 0, name.byteLength());
}

private static EncodingDB.Entry findEncodingOrAliasEntry(ByteList bytes) {
final EncodingDB.Entry e = findEncodingEntry(bytes);
return e != null ? e : findAliasEntry(bytes);
private static EncodingDB.Entry findEncodingOrAliasEntry(Rope name) {
final EncodingDB.Entry e = findEncodingEntry(name);
return e != null ? e : findAliasEntry(name);
}

@TruffleBoundary
private static Encoding loadEncoding(ByteList name) {
private static Encoding loadEncoding(Rope name) {
final EncodingDB.Entry entry = findEncodingOrAliasEntry(name);

if (entry == null) {
Original file line number Diff line number Diff line change
@@ -31,11 +31,18 @@ public abstract class FormatIntegerBinaryNode extends FormatNode {

private final char format;
private final boolean hasPlusFlag;
private final boolean useAlternativeFormat;
private final boolean isLeftJustified;
private final boolean hasSpaceFlag;

public FormatIntegerBinaryNode(RubyContext context, char format, boolean hasPlusFlag) {
public FormatIntegerBinaryNode(RubyContext context, char format, boolean hasPlusFlag, boolean useAlternativeFormat,
boolean isLeftJustified, boolean hasSpaceFlag) {
super(context);
this.format = format;
this.hasPlusFlag = hasPlusFlag;
this.useAlternativeFormat = useAlternativeFormat;
this.isLeftJustified = isLeftJustified;
this.hasSpaceFlag = hasSpaceFlag;
}

@Specialization
@@ -46,7 +53,8 @@ public byte[] format(int spacePadding,
final boolean isNegative = value < 0;
final boolean negativeAndPadded = isNegative && (isSpacePadded || this.hasPlusFlag);
final String formatted = negativeAndPadded ? Integer.toBinaryString(-value) : Integer.toBinaryString(value);
return getFormattedString(formatted, spacePadding, zeroPadding, isNegative, isSpacePadded, this.hasPlusFlag);
return getFormattedString(formatted, spacePadding, zeroPadding, isNegative, isSpacePadded, this.hasPlusFlag,
this.useAlternativeFormat, this.format, this.isLeftJustified, this.hasSpaceFlag);
}

@TruffleBoundary
@@ -57,12 +65,18 @@ public byte[] format(int spacePadding, int zeroPadding, DynamicObject value) {
final boolean isNegative = bigInteger.signum() == -1;
final boolean negativeAndPadded = isNegative && (isSpacePadded || this.hasPlusFlag);
final String formatted = negativeAndPadded ? bigInteger.abs().toString(2) : bigInteger.toString(2);
return getFormattedString(formatted, spacePadding, zeroPadding, isNegative, isSpacePadded, this.hasPlusFlag);
return getFormattedString(formatted, spacePadding, zeroPadding, isNegative, isSpacePadded, this.hasPlusFlag,
this.useAlternativeFormat, this.format, this.isLeftJustified, this.hasSpaceFlag);
}

@TruffleBoundary
private static byte[] getFormattedString(String formatted, int spacePadding, int zeroPadding, boolean isNegative,
boolean isSpacePadded, boolean hasPlusFlag) {
boolean isSpacePadded, boolean hasPlusFlag, boolean useAlternativeFormat,
char format, boolean leftJustified, boolean hasSpaceFlag) {
final boolean isLeftJustified = leftJustified || spacePadding < 0;
if(spacePadding < 0){
spacePadding = -spacePadding;
}
if (isNegative && !(isSpacePadded || hasPlusFlag)) {
if (formatted.contains("0")) {
formatted = formatted.substring(formatted.indexOf('0'), formatted.length());
@@ -82,7 +96,15 @@ private static byte[] getFormattedString(String formatted, int spacePadding, int
}
}

if (isSpacePadded || hasPlusFlag) {
if (useAlternativeFormat) {
if(format == 'B'){
formatted = "0B" + formatted;
} else {
formatted = "0b" + formatted;
}
}

if (hasSpaceFlag || hasPlusFlag) {
if (isNegative) {
formatted = "-" + formatted;
} else {
@@ -91,7 +113,14 @@ private static byte[] getFormattedString(String formatted, int spacePadding, int
} else {
formatted = " " + formatted;
}
}
}

while (formatted.length() < spacePadding) {
if(isLeftJustified){
formatted = formatted + " ";
} else {
formatted = " " + formatted;
}
}

Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
import org.jruby.truffle.core.format.format.FormatFloatNodeGen;
import org.jruby.truffle.core.format.format.FormatIntegerNodeGen;
import org.jruby.truffle.core.format.read.SourceNode;
import org.jruby.truffle.core.format.read.array.ReadArgumentIndexValueNodeGen;
import org.jruby.truffle.core.format.read.array.ReadHashValueNodeGen;
import org.jruby.truffle.core.format.read.array.ReadIntegerNodeGen;
import org.jruby.truffle.core.format.read.array.ReadStringNodeGen;
@@ -86,19 +87,21 @@ public void exitFormat(PrintfParser.FormatContext ctx) {
int spacePadding = DEFAULT;
int zeroPadding = DEFAULT;
boolean hasPlusFlag = false;
boolean hasSpaceFlag = false;
boolean useAlternativeFormat = false;
int absoluteArgumentIndex = DEFAULT;

for (int n = 0; n < ctx.flag().size(); n++) {
final PrintfParser.FlagContext flag = ctx.flag(n);

if (flag.MINUS() != null) {
leftJustified = true;
} else if (flag.SPACE() != null) {
hasSpaceFlag = true;
if (n + 1 < ctx.flag().size() && ctx.flag(n + 1).STAR() != null) {
spacePadding = PADDING_FROM_ARGUMENT;
} else if(width != DEFAULT) {
spacePadding = width;
} else {
spacePadding = 1;
}
} else if (flag.ZERO() != null) {
if (n + 1 < ctx.flag().size() && ctx.flag(n + 1).STAR() != null) {
@@ -107,9 +110,13 @@ public void exitFormat(PrintfParser.FormatContext ctx) {
zeroPadding = width;
}
} else if (flag.STAR() != null) {
// Handled in space and zero, above
spacePadding = PADDING_FROM_ARGUMENT;
} else if (flag.PLUS() != null) {
hasPlusFlag = true;
} else if (flag.HASH() != null) {
useAlternativeFormat = true;
} else if (flag.argumentIndex != null) {
absoluteArgumentIndex = Integer.parseInt(flag.argumentIndex.getText());
} else {
throw new UnsupportedOperationException();
}
@@ -123,12 +130,14 @@ public void exitFormat(PrintfParser.FormatContext ctx) {

final FormatNode valueNode;

if (ctx.ANGLE_KEY() == null) {
valueNode = ReadValueNodeGen.create(context, new SourceNode());
} else {
if (ctx.ANGLE_KEY() != null) {
final byte[] keyBytes = tokenAsBytes(ctx.ANGLE_KEY().getSymbol(), 1);
final DynamicObject key = context.getSymbolTable().getSymbol(context.getRopeTable().getRope(keyBytes, USASCIIEncoding.INSTANCE, CodeRange.CR_7BIT));
valueNode = ReadHashValueNodeGen.create(context, key, new SourceNode());
} else if (absoluteArgumentIndex != DEFAULT){
valueNode = ReadArgumentIndexValueNodeGen.create(context, absoluteArgumentIndex, new SourceNode());
} else {
valueNode = ReadValueNodeGen.create(context, new SourceNode());
}

final int precision;
@@ -216,7 +225,9 @@ public void exitFormat(PrintfParser.FormatContext ctx) {

if(type == 'b' || type == 'B'){
node = WriteBytesNodeGen.create(context,
FormatIntegerBinaryNodeGen.create(context, format, hasPlusFlag,
FormatIntegerBinaryNodeGen.create(context, format, hasPlusFlag, useAlternativeFormat,
leftJustified,
hasSpaceFlag,
spacePaddingNode,
zeroPaddingNode,
ToIntegerNodeGen.create(context, valueNode)));
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2015, 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.format.read.array;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.format.FormatNode;
import org.jruby.truffle.core.format.read.SourceNode;

@NodeChildren({
@NodeChild(value = "source", type = SourceNode.class),
})
public abstract class ReadArgumentIndexValueNode extends FormatNode {

private final int index;

public ReadArgumentIndexValueNode(RubyContext context, int index) {
super(context);
this.index = index - 1;
}

@Specialization
public Object read(VirtualFrame frame, Object[] source) {
return source[this.index];
}

}
Original file line number Diff line number Diff line change
@@ -60,7 +60,6 @@
import org.jruby.truffle.core.cast.NameToSymbolOrStringNodeGen;
import org.jruby.truffle.core.cast.ToPathNodeGen;
import org.jruby.truffle.core.cast.ToStrNodeGen;
import org.jruby.truffle.core.encoding.EncodingNodes;
import org.jruby.truffle.core.encoding.EncodingOperations;
import org.jruby.truffle.core.format.BytesResult;
import org.jruby.truffle.core.format.FormatExceptionTranslator;
@@ -201,7 +200,7 @@ private DynamicObject spawnAndCaptureOutput(DynamicObject command, final Dynamic
}

// TODO (nirvdrum 10-Mar-15) This should be using the default external encoding, rather than hard-coded to UTF-8.
return createString(StringOperations.encodeRope(resultBuilder.toString(), EncodingOperations.getEncoding(EncodingNodes.getEncoding("UTF-8"))));
return createString(StringOperations.encodeRope(resultBuilder.toString(), EncodingOperations.getEncoding(getContext().getEncodingManager().getRubyEncoding("UTF-8"))));
}

}
@@ -653,7 +652,7 @@ private CodeLoader.DeferredCall doEvalX(DynamicObject rubySource,
// TODO (pitr 15-Oct-2015): fix this ugly hack, required for AS, copy-paste
final String space = new String(new char[Math.max(line - 1, 0)]).replace("\0", "\n");
// TODO CS 14-Apr-15 concat space + code as a rope, otherwise the string will be copied after the rope is converted
final Source source = Source.fromText(space + RopeOperations.decodeRope(getContext().getJRubyRuntime(), code), filename);
final Source source = Source.fromText(space + RopeOperations.decodeRope(code), filename);

final MaterializedFrame frame = Layouts.BINDING.getFrame(binding);
final DeclarationContext declarationContext = RubyArguments.getDeclarationContext(frame);
@@ -1394,7 +1393,7 @@ public RubyNode coerceFeatureToPath(RubyNode feature) {
public boolean require(VirtualFrame frame, DynamicObject featureString,
@Cached("create()") RequireNode requireNode) {

String feature = StringOperations.getString(getContext(), featureString);
String feature = StringOperations.getString(featureString);

// Pysch loads either the jar or the so - we need to intercept
if (feature.equals("psych.so") && callerIs("stdlib/psych.rb")) {
@@ -1430,7 +1429,7 @@ public abstract static class RequireRelativeNode extends CoreMethodArrayArgument
@Specialization(guards = "isRubyString(feature)")
public boolean requireRelative(VirtualFrame frame, DynamicObject feature,
@Cached("create()") RequireNode requireNode) {
final String featureString = StringOperations.getString(getContext(), feature);
final String featureString = StringOperations.getString(feature);
final String featurePath = getFullPath(featureString);

return requireNode.executeRequire(frame, featurePath);
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ public boolean load(VirtualFrame frame, DynamicObject file, boolean wrap,
}

try {
final RubyRootNode rootNode = getContext().getCodeLoader().parse(getContext().getSourceCache().getSource(StringOperations.getString(getContext(), file)), UTF8Encoding.INSTANCE, ParserContext.TOP_LEVEL, null, true, this);
final RubyRootNode rootNode = getContext().getCodeLoader().parse(getContext().getSourceCache().getSource(StringOperations.getString(file)), UTF8Encoding.INSTANCE, ParserContext.TOP_LEVEL, null, true, this);
final CodeLoader.DeferredCall deferredCall = getContext().getCodeLoader().prepareExecute(ParserContext.TOP_LEVEL, DeclarationContext.TOP_LEVEL, rootNode, null, getContext().getCoreLibrary().getMainObject());
deferredCall.call(frame, callNode);
} catch (IOException e) {
Original file line number Diff line number Diff line change
@@ -922,7 +922,7 @@ private void loadAutoloadedConstant(VirtualFrame frame, RubyConstant constant) {
requireNode = insert(RequireNode.create());
}

final String feature = StringOperations.getString(getContext(), (DynamicObject) constant.getValue());
final String feature = StringOperations.getString((DynamicObject) constant.getValue());
requireNode.executeRequire(frame, feature);
}

Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.specific.ASCIIEncoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.rope.Rope;
@@ -59,9 +61,9 @@ private DynamicObject createRegexp(DynamicObject[] parts) {
final Rope source = Layouts.REGEXP.getSource(regexp);

if (!BodyTranslator.all7Bit(preprocessed.getByteList().bytes())) {
Layouts.REGEXP.setSource(regexp, RopeOperations.withEncodingVerySlow(source, getContext().getJRubyRuntime().getEncodingService().getAscii8bitEncoding()));
Layouts.REGEXP.setSource(regexp, RopeOperations.withEncodingVerySlow(source, ASCIIEncoding.INSTANCE));
} else {
Layouts.REGEXP.setSource(regexp, RopeOperations.withEncodingVerySlow(source, getContext().getJRubyRuntime().getEncodingService().getUSAsciiEncoding()));
Layouts.REGEXP.setSource(regexp, RopeOperations.withEncodingVerySlow(source, USASCIIEncoding.INSTANCE));
}
}

Original file line number Diff line number Diff line change
@@ -28,10 +28,10 @@
import org.jcodings.specific.ASCIIEncoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.Ruby;
import org.jruby.RubyEncoding;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.encoding.EncodingManager;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.util.ByteList;
@@ -124,7 +124,7 @@ public static String decodeUTF8(byte[] bytes, int offset, int byteLength) {
}

@TruffleBoundary
public static String decodeRope(Ruby runtime, Rope value) {
public static String decodeRope(Rope value) {
// TODO CS 9-May-16 having recursive problems with this, so flatten up front for now

value = flatten(value);
@@ -142,7 +142,7 @@ public static String decodeRope(Ruby runtime, Rope value) {
Charset charset = encodingToCharsetMap.get(encoding);

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

@@ -594,7 +594,7 @@ public static Rope format(RubyContext context, Object... values) {
|| encoding == ASCIIEncoding.INSTANCE) {
valueRope = stringRope;
} else {
valueRope = StringOperations.encodeRope(decodeRope(context.getJRubyRuntime(), stringRope), UTF8Encoding.INSTANCE);
valueRope = StringOperations.encodeRope(decodeRope(stringRope), UTF8Encoding.INSTANCE);
}
} else if (value instanceof Integer) {
valueRope = new LazyIntRope((int) value);
Original file line number Diff line number Diff line change
@@ -190,7 +190,7 @@ public static abstract class IOOpenPrimitiveNode extends IOPrimitiveArrayArgumen
@TruffleBoundary(throwsControlFlowException = true)
@Specialization(guards = "isRubyString(path)")
public int open(DynamicObject path, int mode, int permission) {
return ensureSuccessful(posix().open(StringOperations.getString(getContext(), path), mode, permission));
return ensureSuccessful(posix().open(StringOperations.getString(path), mode, permission));
}

}
@@ -201,7 +201,7 @@ public static abstract class IOTruncatePrimitiveNode extends IOPrimitiveArrayArg
@TruffleBoundary(throwsControlFlowException = true)
@Specialization(guards = "isRubyString(path)")
public int truncate(DynamicObject path, long length) {
return ensureSuccessful(posix().truncate(StringOperations.getString(getContext(), path), length));
return ensureSuccessful(posix().truncate(StringOperations.getString(path), length));
}

}
@@ -342,7 +342,7 @@ public IOReopenPathPrimitiveNode(RubyContext context, SourceSection sourceSectio
public void performReopenPath(DynamicObject self, DynamicObject path, int mode) {
final int fdSelf = Layouts.IO.getDescriptor(self);
final int newFdSelf;
final String targetPathString = StringOperations.getString(getContext(), path);
final String targetPathString = StringOperations.getString(path);

int fdTarget = ensureSuccessful(posix().open(targetPathString, mode, 0_666));

Original file line number Diff line number Diff line change
@@ -831,7 +831,6 @@ public Object crypt(DynamicObject string, DynamicObject salt) {
final Rope value = rope(string);
final Rope other = rope(salt);

final Encoding ascii8bit = getContext().getJRubyRuntime().getEncodingService().getAscii8bitEncoding();
if (other.byteLength() < 2) {
CompilerDirectives.transferToInterpreterAndInvalidate();
throw new RaiseException(coreExceptions().argumentError("salt too short (need >= 2 bytes)", this));
@@ -860,7 +859,7 @@ public Object crypt(DynamicObject string, DynamicObject salt) {
taintResultNode = insert(new TaintResultNode(getContext(), getSourceSection()));
}

final DynamicObject ret = createString(StringOperations.ropeFromByteList(new ByteList(cryptedString, 0, cryptedString.length - 1, ascii8bit, false)));
final DynamicObject ret = createString(StringOperations.ropeFromByteList(new ByteList(cryptedString, 0, cryptedString.length - 1, ASCIIEncoding.INSTANCE, false)));

taintResultNode.maybeTaint(string, ret);
taintResultNode.maybeTaint(salt, ret);
@@ -1138,7 +1137,7 @@ public abstract static class EncodingNode extends CoreMethodArrayArgumentsNode {

@Specialization
public DynamicObject encoding(DynamicObject string) {
return EncodingNodes.getEncoding(StringOperations.encoding(string));
return getContext().getEncodingManager().getRubyEncoding(StringOperations.encoding(string));
}

}
@@ -1159,7 +1158,7 @@ public ForceEncodingNode(RubyContext context, SourceSection sourceSection) {
public DynamicObject forceEncodingString(DynamicObject string, DynamicObject encodingName,
@Cached("createBinaryProfile()") ConditionProfile differentEncodingProfile,
@Cached("createBinaryProfile()") ConditionProfile mutableRopeProfile) {
final DynamicObject encoding = EncodingNodes.getEncoding(encodingName.toString());
final DynamicObject encoding = getContext().getEncodingManager().getRubyEncoding(encodingName.toString());
return forceEncodingEncoding(string, encoding, differentEncodingProfile, mutableRopeProfile);
}

Original file line number Diff line number Diff line change
@@ -70,9 +70,9 @@ public static DynamicObject createString(RubyContext context, Rope rope) {
}

// Since ByteList.toString does not decode properly
@CompilerDirectives.TruffleBoundary
public static String getString(RubyContext context, DynamicObject string) {
return RopeOperations.decodeRope(context.getJRubyRuntime(), StringOperations.rope(string));
@TruffleBoundary
public static String getString(DynamicObject string) {
return RopeOperations.decodeRope(StringOperations.rope(string));
}

public static StringCodeRangeableWrapper getCodeRangeableReadWrite(final DynamicObject string) {
Original file line number Diff line number Diff line change
@@ -73,7 +73,7 @@ public abstract static class EncodingNode extends CoreMethodArrayArgumentsNode {

@Specialization
public DynamicObject encoding(DynamicObject symbol) {
return EncodingNodes.getEncoding(Layouts.SYMBOL.getRope(symbol).getEncoding());
return getContext().getEncodingManager().getRubyEncoding(Layouts.SYMBOL.getRope(symbol).getEncoding());
}

}
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ protected DateTimeZone getTimeZone(VirtualFrame frame) {
if (tz == nil()) {
return DateTimeZone.getDefault();
} else if (RubyGuards.isRubyString(tz)) {
return TimeZoneParser.parse(this, StringOperations.getString(getContext(), (DynamicObject) tz));
return TimeZoneParser.parse(this, StringOperations.getString((DynamicObject) tz));
} else {
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -28,8 +28,8 @@ public abstract static class HashPassword extends CoreMethodArrayArgumentsNode {
@Specialization(guards = { "isRubyString(secret)", "isRubyString(salt)" })
public Object hashpw(DynamicObject secret, DynamicObject salt) {
final String result = BCrypt.hashpw(
StringOperations.getString(getContext(), secret),
StringOperations.getString(getContext(), salt));
StringOperations.getString(secret),
StringOperations.getString(salt));
return StringOperations.createString(
getContext(),
StringOperations.createRope(result, USASCIIEncoding.INSTANCE));
2 changes: 2 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/language/Options.java
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
import static org.jruby.util.cli.Options.TRUFFLE_COVERAGE_GLOBAL;
import static org.jruby.util.cli.Options.TRUFFLE_DISPATCH_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_ENCODING_COMPATIBLE_QUERY_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_ENCODING_LOADED_CLASSES_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_EVAL_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_EXCEPTIONS_PRINT_JAVA;
import static org.jruby.util.cli.Options.TRUFFLE_EXCEPTIONS_PRINT_UNCAUGHT_JAVA;
@@ -121,6 +122,7 @@ public class Options {
public final int EVAL_CACHE = TRUFFLE_EVAL_CACHE.load();
public final int CLASS_CACHE = TRUFFLE_CLASS_CACHE.load();
public final int ENCODING_COMPATIBILE_QUERY_CACHE = TRUFFLE_ENCODING_COMPATIBLE_QUERY_CACHE.load();
public final int ENCODING_LOADED_CLASSES_CACHE = TRUFFLE_ENCODING_LOADED_CLASSES_CACHE.load();
public final int THREAD_CACHE = TRUFFLE_THREAD_CACHE.load();
public final int ROPE_CLASS_CACHE = TRUFFLE_ROPE_CLASS_CACHE.load();
public final int INTEROP_CONVERT_CACHE = TRUFFLE_INTEROP_CONVERT_CACHE.load();
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ public String toString(DynamicObject object) {
CompilerAsserts.neverPartOfCompilation();

if (RubyGuards.isRubyString(object)) {
return RopeOperations.decodeRope(getContext().getJRubyRuntime(), StringOperations.rope(object));
return RopeOperations.decodeRope(StringOperations.rope(object));
} else if (RubyGuards.isRubySymbol(object)) {
return Layouts.SYMBOL.getString(object);
} else if (RubyGuards.isRubyException(object)) {
@@ -45,12 +45,4 @@ public ForeignAccess getForeignAccessFactory(DynamicObject object) {
return RubyMessageResolutionAccessor.ACCESS;
}

public static boolean isInstance(TruffleObject object) {
return RubyGuards.isRubyBasicObject(object);
}

private RubyContext getContext() {
return Layouts.MODULE.getFields(Layouts.BASIC_OBJECT.getLogicalClass(this)).getContext();
}

}
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ protected Object autoloadConstant(VirtualFrame frame, DynamicObject module, Stri
// We remove it first to allow lookup to ignore it and add it back if there was a failure.
Layouts.MODULE.getFields(constant.getDeclaringModule()).removeConstant(getContext(), this, name);
try {
requireNode.executeRequire(frame, StringOperations.getString(getContext(), path));
requireNode.executeRequire(frame, StringOperations.getString(path));
final RubyConstant resolvedConstant = lookupConstantNode.lookupConstant(frame, module, name);
return executeGetConstant(frame, module, name, resolvedConstant, lookupConstantNode);
} catch (RaiseException e) {
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ public RubyConstant lookupForExistingModule(VirtualFrame frame, String name, Dyn
// call or the recursive execute call.

Layouts.MODULE.getFields(lexicalParent).removeConstant(getContext(), this, name);
getRequireNode().executeRequire(frame, StringOperations.getString(getContext(), (DynamicObject) constant.getValue()));
getRequireNode().executeRequire(frame, StringOperations.getString((DynamicObject) constant.getValue()));
return deepConstantSearch(name, lexicalParent);
}

Original file line number Diff line number Diff line change
@@ -1353,7 +1353,7 @@ public RubyNode visitDotNode(org.jruby.ast.DotNode node) {
@Override
public RubyNode visitEncodingNode(org.jruby.ast.EncodingNode node) {
SourceSection sourceSection = translate(node.getPosition());
final RubyNode ret = new ObjectLiteralNode(context, sourceSection, EncodingNodes.getEncoding(node.getEncoding()));
final RubyNode ret = new ObjectLiteralNode(context, sourceSection, context.getEncodingManager().getRubyEncoding(node.getEncoding()));
return addNewlineIfNeeded(node, ret);
}

Original file line number Diff line number Diff line change
@@ -53,6 +53,7 @@
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.adapaters.OutputStreamAdapter;
import org.jruby.truffle.core.array.ArrayOperations;
import org.jruby.truffle.core.encoding.EncodingManager;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
@@ -143,7 +144,7 @@ public DynamicObject startStream(DynamicObject emitter, int encodingOrdinal) {
}

final Encoding encoding = YAMLEncoding.values()[encodingOrdinal].getEncoding();
final Charset charset = getContext().getJRubyRuntime().getEncodingService().charsetForEncoding(encoding);
final Charset charset = EncodingManager.charsetForEncoding(encoding);

Layouts.PSYCH_EMITTER.setEmitter(emitter,
new Emitter(

0 comments on commit b965b0c

Please sign in to comment.