Skip to content

Commit

Permalink
Showing 77 changed files with 2,131 additions and 428 deletions.
73 changes: 73 additions & 0 deletions bench/java/bench_java_coll_member.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require 'java'
require 'benchmark'

TIMES = (ARGV[0] || 5).to_i

CONTENTS = (1..36).to_a

TIMES.times do
Benchmark.bm(10) do |bm|
bm.report('ArrayList#include? hit ') do
list = java.util.ArrayList.new CONTENTS
hit = 32
1_000_000.times { list.include?(hit) }
end
bm.report('ArrayList#include? miss') do
list = java.util.ArrayList.new CONTENTS
miss = 0
1_000_000.times { list.include?(miss) }
end
bm.report('ArrayList#contains hit ') do
list = java.util.ArrayList.new CONTENTS
hit = 32
1_000_000.times { list.contains(hit) }
end
bm.report('ArrayList#contains miss') do
list = java.util.ArrayList.new CONTENTS
miss = 0
1_000_000.times { list.contains(miss) }
end

bm.report('HashSet#include? hit ') do
list = java.util.HashSet.new CONTENTS
hit = 32
1_000_000.times { list.include?(hit) }
end
bm.report('HashSet#include? miss ') do
list = java.util.HashSet.new CONTENTS
miss = 0
1_000_000.times { list.include?(miss) }
end
bm.report('HashSet#contains hit ') do
list = java.util.HashSet.new CONTENTS
hit = 32
1_000_000.times { list.contains(hit) }
end
bm.report('HashSet#contains miss ') do
list = java.util.HashSet.new CONTENTS
miss = 0
1_000_000.times { list.contains(miss) }
end

bm.report('LHashSet#include? hit ') do
list = java.util.LinkedHashSet.new CONTENTS
hit = 32
1_000_000.times { list.include?(hit) }
end
bm.report('LHashSet#include? miss ') do
list = java.util.LinkedHashSet.new CONTENTS
miss = 0
1_000_000.times { list.include?(miss) }
end
bm.report('LHashSet#contains hit ') do
list = java.util.LinkedHashSet.new CONTENTS
hit = 32
1_000_000.times { list.contains(hit) }
end
bm.report('LHashSet#contains miss ') do
list = java.util.LinkedHashSet.new CONTENTS
miss = 0
1_000_000.times { list.contains(miss) }
end
end
end
45 changes: 45 additions & 0 deletions bench/java/bench_java_list_ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'java'
require 'benchmark'

TIMES = (ARGV[0] || 5).to_i

TIMES.times do
Benchmark.bm(10) do |bm|
bm.report('ArrayList') do
list = java.util.ArrayList.new
one = 1.to_java
two = 2.to_java
thr = 3.to_java
1_000_000.times do
list.clear

list << one; list << two; list << thr

list[2] = one; list[0] = two; list[1] = thr

list.index(one)
list.rindex(thr)

list.to_a
end
end
bm.report('LinkedList') do
list = java.util.LinkedList.new
one = 1.to_java
two = 2.to_java
thr = 3.to_java
1_000_000.times do
list.clear

list << one; list << two; list << thr

list[2] = one; list[0] = two; list[1] = thr

list.index(one)
list.rindex(thr)

list.to_a
end
end
end
end
9 changes: 6 additions & 3 deletions ci.hocon
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ common: {

setup: ${common-setup}

timelimit: "00:30:00"
timelimit: "01:00:00"
}

no-graal: {
@@ -285,16 +285,19 @@ test-cexts: {
[cd, ../..],
[mv, temp_mx, mx.jruby]
[mx, sclone, --kind, git, "https://github.com/jruby/jruby-truffle-gem-test-pack.git", jruby-truffle-gem-test-pack],
${jt} [build, cexts]
${jt} [build, cexts, --no-openssl]
]

environment: {
GEM_HOME: jruby-truffle-gem-test-pack/gems
GRAAL_HOME: sulong-workspace/sulong,
SULONG_HOME: sulong-workspace/sulong,
SULONG_NO_LIBRARY: "true",
USE_SYSTEM_CLANG: "true",
HOST_VM: server,
HOST_VM_CONFIG: graal-core
HOST_VM_CONFIG: graal-core,
LIBXML_LIB: "/usr/lib64/libxml2.so.2",
OPENSSL_LIB: "/usr/lib64/libssl.so.10"
}

run: [
2 changes: 1 addition & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@

jar 'org.jruby.joni:joni:2.1.10'
jar 'org.jruby.extras:bytelist:1.0.13'
jar 'org.jruby.jcodings:jcodings:1.0.17'
jar 'org.jruby.jcodings:jcodings:1.0.18-SNAPSHOT'
jar 'org.jruby:dirgra:0.3'

jar 'com.headius:invokebinder:1.7'
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
@@ -184,7 +184,7 @@ DO NOT MODIFIY - GENERATED CODE
<dependency>
<groupId>org.jruby.jcodings</groupId>
<artifactId>jcodings</artifactId>
<version>1.0.17</version>
<version>1.0.18-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1899,6 +1899,8 @@ protected void receiveNonBlockArgs(final ArgsNode argsNode) {
// We add this extra nil copy because we do not know if we have a circular defininition of
// argVar: proc { |a=a| } or proc { |a = foo(bar(a))| }.
addInstr(new CopyInstr(argVar, manager.getNil()));
// This bare build looks weird but OptArgNode is just a marker and value is either a LAsgnNode
// or a DAsgnNode. So building the value will end up having a copy(var, assignment).
build(optArg.getValue());
addInstr(new LabelInstr(variableAssigned));
}
3 changes: 0 additions & 3 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -826,9 +826,6 @@ public static RubyModule findInstanceMethodContainer(ThreadContext context, Dyna
// in b65a5842ecf56ca32edc2a17800968f021b6a064. At that time,
// I was wondering if it would affect this site here and looks
// like it does.
//
// Verify that the test in GH issue 4014 runs when ripping out
// this special instanceof check below.
return self instanceof RubyModule ? (RubyModule) self : self.getMetaClass();

case INSTANCE_METHOD:
13 changes: 13 additions & 0 deletions core/src/main/java/org/jruby/javasupport/ext/JavaLang.java
Original file line number Diff line number Diff line change
@@ -117,6 +117,19 @@ public static IRubyObject each_with_index(final ThreadContext context, final IRu
return context.nil;
}

@JRubyMethod(name = { "to_a", "entries" })
public static IRubyObject to_a(final ThreadContext context, final IRubyObject self, final Block block) {
final Ruby runtime = context.runtime;
final RubyArray ary = runtime.newArray();
java.lang.Iterable iterable = unwrapJavaObject(self);
java.util.Iterator iterator = iterable.iterator();
while ( iterator.hasNext() ) {
final Object value = iterator.next();
ary.append( convertJavaToUsableRubyObject(runtime, value) );
}
return ary;
}

}

@JRubyClass(name = "Java::JavaLang::Comparable", include = "Comparable")
10 changes: 8 additions & 2 deletions core/src/main/java/org/jruby/javasupport/ext/JavaUtil.java
Original file line number Diff line number Diff line change
@@ -137,6 +137,12 @@ public static IRubyObject each_with_index(final ThreadContext context, final IRu
return JavaLang.Iterable.each_with_index(context, self, block);
}

@JRubyMethod(name = { "include?", "member?" }) // @override Enumerable#include?
public static RubyBoolean include_p(final ThreadContext context, final IRubyObject self, final IRubyObject obj) {
final java.util.Collection coll = unwrapJavaObject(self);
return context.runtime.newBoolean( coll.contains( obj.toJava(java.lang.Object.class) ) );
}

// NOTE: first might conflict with some Java types (e.g. java.util.Deque) thus providing a ruby_ alias
@JRubyMethod(name = { "first", "ruby_first" }) // re-def Enumerable#first
public static IRubyObject first(final ThreadContext context, final IRubyObject self) {
@@ -165,13 +171,13 @@ public static IRubyObject append(final IRubyObject self, final IRubyObject item)
return self;
}

@JRubyMethod
@JRubyMethod(name = { "to_a", "entries" })
public static RubyArray to_a(final ThreadContext context, final IRubyObject self) {
final Object[] array = ((java.util.Collection) unwrapJavaObject(self)).toArray();
if ( IRubyObject.class.isAssignableFrom(array.getClass().getComponentType()) ) {
return RubyArray.newArrayMayCopy(context.runtime, (IRubyObject[]) array);
}
return RubyArray.newArrayMayCopy(context.runtime, convertJavaArrayToRuby(context.runtime, array));
return RubyArray.newArrayNoCopy(context.runtime, convertJavaArrayToRuby(context.runtime, array));
}

@JRubyMethod(name = "+", required = 1)
10 changes: 10 additions & 0 deletions core/src/main/ruby/jruby/java/java_ext/java.util.rb
Original file line number Diff line number Diff line change
@@ -19,6 +19,16 @@ def each_with_index(&block)
# stub implemented in org.jruby.javasupport.ext.JavaUtil.java
end

# Re-implemented for efficiency, so that we do not (`#each`) loop over the collection
# for types where its not necessary (e.g. *java.util.Set* instances), using (native) `contains`.
# @see Java::java::lang::Iterable#include?
# @return [true, false]
# @since 9.1.3
def include?(obj)
# stub implemented in org.jruby.javasupport.ext.JavaUtil.java
end
alias member? include?

# `Enumerable#first`
# @note Might collide with *java.util.Deque#getFirst* in which case you want to alias its ruby_ name
# so that the Ruby version is used e.g. `java.util.ArrayDeque.class_eval { alias first ruby_first }`
438 changes: 398 additions & 40 deletions lib/ruby/truffle/cext/ruby.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/ruby/truffle/cext/ruby/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "../ruby.h"
1 change: 1 addition & 0 deletions lib/ruby/truffle/cext/ruby/io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "../ruby.h"
1 change: 1 addition & 0 deletions lib/ruby/truffle/cext/ruby/thread.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "../ruby.h"
1 change: 1 addition & 0 deletions lib/ruby/truffle/cext/ruby/thread_native.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "../ruby.h"
6 changes: 5 additions & 1 deletion lib/ruby/truffle/cext/version.h
Original file line number Diff line number Diff line change
@@ -6,6 +6,10 @@
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*
* This file contains code that is based on the Ruby API headers,
* copyright (C) Yukihiro Matsumoto, licensed under the 2-clause BSD licence
* as described in the file BSDL included with JRuby+Truffle.
*/

#ifndef TRUFFLE_VERSION_H
@@ -17,4 +21,4 @@
#define RUBY_API_VERSION_TEENY 0
#define RUBY_API_VERSION_CODE (RUBY_API_VERSION_MAJOR*10000+RUBY_API_VERSION_MINOR*100+RUBY_API_VERSION_TEENY)

#endif
#endif
Original file line number Diff line number Diff line change
@@ -47,17 +47,13 @@ CookiesTest:
- test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
- test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set
- test_legacy_signed_cookie_is_read_and_transparently_upgraded_by_signed_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
- test_wrapped_encrypted_cookie_using_json_serializer
- test_encrypted_cookie_using_json_serializer
- test_wrapped_encrypted_cookie_using_json_serializer # fails on CI
- test_encrypted_cookie_using_json_serializer # fails on CI
DebugExceptionsTest:
- test_debug_exceptions_app_shows_user_code_that_caused_the_error_in_source_view
- test_display_backtrace_on_template_missing_errors
- test_display_backtrace_when_error_type_is_SyntaxError
- test_display_backtrace_when_error_type_is_SyntaxError_wrapped_by_ActionView
- test_displays_request_and_response_info_when_a_RoutingError_occurs
- test_rescue_with_diagnostics_message
- test_rescue_with_text_error_for_xhr_request
- test_show_registered_original_exception_for_wrapped_exceptions
- test_display_backtrace_when_error_type_is_SyntaxError_wrapped_by_ActionView::Template::Error
TestRoutingMapper:
- test_redirect_modulo
@@ -72,22 +68,18 @@ CookieStoreTest:
- test_deserializes_unloaded_classes_on_get_id
- test_deserializes_unloaded_classes_on_get_value
StaticTest:
- test_serves_gzip_files_when_header_set
- test_serves_gzip_with_propper_content_type_fallback
- test_serves_gzip_files_when_header_set # fails on travis
- test_serves_gzip_with_propper_content_type_fallback # fails on travis
StaticEncodingTest:
- test_serves_gzip_files_when_header_set
- test_serves_gzip_with_propper_content_type_fallback
- test_serves_gzip_files_when_header_set # fails on travis
- test_serves_gzip_with_propper_content_type_fallback # fails on travis
TestGenerationPrefix::WithMountedEngine:
- test_[ENGINE]_absolute_path_redirect_doesn't_use_SCRIPT_NAME_from_request
- test_[ENGINE]_absolute_path_root_doesn't_use_SCRIPT_NAME_from_request
- test_[ENGINE]_relative_path_redirect_uses_SCRIPT_NAME_from_request
ActionController::LiveStreamTest:
- test_exception_callback_when_committed
- test_abort_with_full_buffer # hangs sometimes
- test_async_stream # intermittent on travis
- test_stale_without_etag # hangs sometimes
- test_async_stream # fails on travis
ApplicationIntegrationTest:
- test_missing_route_helper_after_controller_access
- test_missing_route_helper_before_controller_access
HttpDigestAuthenticationTest:
- authentication_request_with_invalid_realm # hangs sometimes
25 changes: 13 additions & 12 deletions lib/ruby/truffle/jruby+truffle/lib/truffle/config.rb
Original file line number Diff line number Diff line change
@@ -234,36 +234,37 @@ def compute_physical_processor_count


class Truffle::Runner::CIEnvironment
def rails_ci(exclude)
repository_name 'rails'
def rails_ci
declare_options debug: ['--[no-]debug', 'Run tests with remote debugging enabled.',
STORE_NEW_VALUE, false],
exclude: ['--[no-]exclude', 'Exclude known failing tests',
STORE_NEW_VALUE, true]

repository_name 'rails'

use_only_https_git_paths!

has_to_succeed setup
set_result run([%w[--require-pattern test/**/*_test.rb],
(exclude ? %w[-r excluded-tests] : []),
%w[-- -I test -e nil]].flatten(1))
set_result run([*%w[--require-pattern test/**/*_test.rb],
*(%w[-r excluded-tests] if option(:exclude)),
*(%w[--debug] if option(:debug)),
*%w[-- -I test -e nil]])
end
end

Truffle::Runner.add_ci_definition :actionpack do
declare_options exclude: ['--[no-]exclude',
'Exclude known failing tests',
STORE_NEW_VALUE,
true]
subdir 'actionpack'
rails_ci option(:exclude)
rails_ci
end

Truffle::Runner.add_ci_definition :activemodel do
subdir 'activemodel'
rails_ci false
rails_ci
end

Truffle::Runner.add_ci_definition :activesupport do
subdir 'activesupport'
rails_ci false
rails_ci
end

Truffle::Runner.add_ci_definition :algebrick do
38 changes: 38 additions & 0 deletions spec/java_integration/extensions/collection_spec.rb
Original file line number Diff line number Diff line change
@@ -79,6 +79,9 @@
coll = java.util.ArrayDeque.new(@data)
expect(coll.to_a).to eq(@data.to_a)

coll = java.util.LinkedHashSet.new(@data)
expect(coll.entries).to eq(@data.to_a)

coll = java.util.HashSet.new
expect(coll.to_a).to eq([])
end
@@ -154,6 +157,41 @@
expect( set.to_a ).to eql ['0']
end

it '#include?' do
set = java.util.LinkedHashSet.new [1, 2, 3]
expect( set.include? 1 ).to be true
expect( set.member? 2 ).to be true
expect( set.contains 3 ).to be true
set.add 4; set.add 5.to_java
expect( set.include? 4 ).to be true
expect( set.include? 5 ).to be true
expect( set.contains 4 ).to be true
expect( set.contains 5 ).to be true
expect( set.contains 4.to_java ).to be true
expect( set.contains 5.to_java ).to be true
expect( set.contains 5.to_java(:byte) ).to be false
expect( set.contains 5.to_java(:short) ).to be false
expect( set.contains 6 ).to be false
expect( set.include? 6 ).to be false
expect( set.include? 4.to_java(:byte) ).to be false
expect( set.include? 4.to_java(:short) ).to be false
expect( set.include? 2.to_java ).to be true
expect( set.include? 2.to_java(:short) ).to be false
end

it '#include? (specific)' do
pending 'due Java numeric conversion can not add to_java(:xxx) to collection'

set = java.util.LinkedHashSet.new [2]
set << 1.to_java(:short)
expect( set.include? 1.to_java ).to be true
expect( set.include? 1.to_java(:short) ).to be true

set.add 3.to_java(:short)
expect( set.contains 3.to_java ).to be true
expect( set.contains 3.to_java(:short) ).to be true
end

it "should respect to_ary objects defined on iteration" do
class Pair
def initialize(a, b)
15 changes: 15 additions & 0 deletions spec/java_integration/extensions/iterable_spec.rb
Original file line number Diff line number Diff line change
@@ -47,4 +47,19 @@
expect( paths.last ).to eq 'ITERABLE_SPEC.RB'
end

it 'converts #to_a' do
file_system = java.nio.file.FileSystems.getDefault
path = file_system.getPath(__FILE__)
expect( path.to_a ).to_not be_empty
expect( path.to_a ).to eql iterate_path(path)
end

private

def iterate_path(path)
res = [] ; it = path.iterator
while it.hasNext ; res << it.next end
res
end

end
23 changes: 23 additions & 0 deletions spec/regression/GH-4014_method_define_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Regression spec courtesy Jason Lunn for GH issue 4104
module DefinesMethod
def def_meth &block
define_method :foo, &block
end
end

class RegressionTest
extend DefinesMethod
def_meth do
def bar
'Success'
end
end
end

describe "Method defined inside an instance method" do
it "should succeed even when that instance method is generated via define_method" do
o = RegressionTest.new
o.foo
expect(o.bar).to eq "Success"
end
end
1 change: 1 addition & 0 deletions spec/ruby/core/class/dup_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)

# NOTE: This is actually implemented by Module#initialize_copy
describe "Class#dup" do
it "duplicates both the class and the singleton class" do
klass = Class.new do
3 changes: 0 additions & 3 deletions spec/ruby/optional/capi/ext/jruby_truffle.h
Original file line number Diff line number Diff line change
@@ -175,7 +175,6 @@
#undef HAVE_RB_OBJ_ENCODING

#undef HAVE_RB_STR_ENCODE
#undef HAVE_RB_STR_NEW_CSTR
#undef HAVE_RB_USASCII_STR_NEW
#undef HAVE_RB_USASCII_STR_NEW_CSTR
#undef HAVE_RB_EXTERNAL_STR_NEW
@@ -409,8 +408,6 @@
#undef HAVE_RB_STR_UPDATE
#undef HAVE_RB_STR_INSPECT
#undef HAVE_RB_STR_INTERN
#undef HAVE_RB_STR_NEW
#undef HAVE_RB_STR_NEW2
#undef HAVE_RB_STR_NEW3
#undef HAVE_RB_STR_NEW4
#undef HAVE_RB_STR_NEW5
3 changes: 2 additions & 1 deletion spec/ruby/optional/capi/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -110,7 +110,8 @@ def compile_extension_jruby_truffle(name)
f.puts "out: #{output_file}"
end

system "#{RbConfig::CONFIG['bindir']}/jruby", "#{RbConfig::CONFIG['bindir']}/../tool/jt.rb", 'cextc', extension_path
system "#{RbConfig::CONFIG['bindir']}/../tool/jt.rb", 'cextc', extension_path
raise "Compilation of #{extension_path} failed" unless $?.success?

output_file
ensure
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/comparable/equal_value_tags.txt

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/exception/no_method_error_tags.txt

This file was deleted.

8 changes: 0 additions & 8 deletions spec/truffle/tags/core/exception/receiver_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/exception/to_s_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/fixnum/bit_xor_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/random/bytes_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/struct/dup_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/systemexit/initialize_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/optional/capi/string_tags.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
fails:C-API String function rb_str_set_len reduces the size of the string
fails:C-API String function rb_str_set_len inserts a NULL byte at the length
fails:C-API String function rb_str_set_len updates the string's attributes visible in C code
fails:C-API String function rb_str_buf_new returns the equivalent of an empty string
fails:C-API String function rb_str_buf_new returns a string that can be appended to
fails:C-API String function rb_str_buf_new returns a string that can be concatenated to another string
fails:C-API String function rb_str_buf_new returns a string whose bytes can be accessed by RSTRING_PTR
fails:C-API String function rb_str_buf_new returns a string that can be modified by rb_str_set_len
fails:C-API String function rb_str_buf_new2 returns a new string object calling strlen on the passed C string
fails:C-API String function rb_str_new returns a new string object from a char buffer of len characters
fails:C-API String function rb_str_new returns an empty string if len is 0
fails:C-API String function rb_str_new2 returns a new string object calling strlen on the passed C string
fails:C-API String function rb_str_new2 encodes the string with ASCII_8BIT
fails:C-API String function rb_str_new creates a new String with ASCII-8BIT Encoding
fails:C-API String function rb_str_new_cstr returns a new string object calling strlen on the passed C string
fails:C-API String function rb_str_new_cstr encodes the string with ASCII_8BIT
fails:C-API String function rb_usascii_str_new creates a new String with US-ASCII Encoding from a char buffer of len characters
@@ -53,7 +49,6 @@ fails:C-API String function rb_str_subseq returns a byte-indexed substring
fails:C-API String function rb_str_substr returns a substring
fails:C-API String function rb_str_to_str calls #to_str to coerce the value to a String
fails:C-API String function rb_str_to_str raises a TypeError if coercion fails
fails:C-API String function RSTRING_LEN returns the size of the string
fails:C-API String function RSTRING_LENINT returns the size of a string
fails:C-API String function StringValue does not call #to_str on a String
fails:C-API String function StringValue does not call #to_s on a String
4 changes: 2 additions & 2 deletions test/truffle/cexts/nokogiri/.jruby-cext-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
src: $GEM_HOME/gems/nokogiri-1.6.8/ext/nokogiri/*.c
cflags: -I$GEM_HOME/gems/nokogiri-1.6.8/ext/nokogiri -I$LIBXML_HOME/include/libxml2
libs: $LIBXML_HOME/lib/libxml2.dylib
cflags: -I$GEM_HOME/gems/nokogiri-1.6.8/ext/nokogiri -I$LIBXML_INCLUDE
libs: $LIBXML_LIB
out: lib/nokogiri/nokogiri.su
4 changes: 2 additions & 2 deletions test/truffle/cexts/xml/.jruby-cext-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
src: ext/xml/*.c
cflags: -I$LIBXML_HOME/include/libxml2
libs: $LIBXML_LIB_HOME/libxml2.so
cflags: -I$LIBXML_INCLUDE
libs: $LIBXML_LIB
out: lib/xml/xml.su
4 changes: 2 additions & 2 deletions test/truffle/cexts/xopenssl/.jruby-cext-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
src: ext/xopenssl/*.c
cflags: -I$OPENSSL_HOME/include
libs: $OPENSSL_LIB_HOME/libssl.so
cflags: -I$OPENSSL_INCLUDE
libs: $OPENSSL_LIB
out: lib/xopenssl/xopenssl.su
4 changes: 1 addition & 3 deletions test/truffle/ecosystem/batch.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
---
# TODO (pitr-ch 19-Jul-2016): reenable after tests stop randomly hanging
# - actionpack

- actionpack
- activesupport
- activemodel
- algebrick
117 changes: 81 additions & 36 deletions tool/jt.rb
Original file line number Diff line number Diff line change
@@ -31,13 +31,23 @@
JEXCEPTION = "-Xtruffle.exceptions.print_java=true"
METRICS_REPS = 10

MAC = `uname -a`.include?('Darwin')

if MAC
SO = 'dylib'
else
SO = 'so'
end

LIBXML_HOME = ENV['LIBXML_HOME'] = ENV['LIBXML_HOME'] || '/usr'
LIBXML_LIB_HOME = ENV['LIBXML_LIB_HOME'] = ENV['LIBXML_LIB_HOME'] || "#{LIBXML_HOME}/lib"
LIBXML_INCLUDE = ENV['LIBXML_INCLUDE'] = ENV['LIBXML_INCLUDE'] || "#{LIBXML_HOME}/include/libxml2"
LIBXML_LIB = ENV['LIBXML_LIB'] = ENV['LIBXML_LIB'] || "#{LIBXML_LIB_HOME}/libxml2.#{SO}"

OPENSSL_HOME = ENV['OPENSSL_HOME'] = ENV['OPENSSL_HOME'] || '/usr'
OPENSSL_LIB_HOME = ENV['OPENSSL_LIB_HOME'] = ENV['OPENSSL_LIB_HOME'] || "#{OPENSSL_HOME}/lib"

MAC = `uname -a`.include?('Darwin')
OPENSSL_INCLUDE = ENV['OPENSSL_INCLUDE'] = ENV['OPENSSL_INCLUDE'] || "#{OPENSSL_HOME}/include"
OPENSSL_LIB = ENV['OPENSSL_LIB'] = ENV['OPENSSL_LIB'] || "#{OPENSSL_LIB_HOME}/libssl.#{SO}"

# wait for sub-processes to handle the interrupt
trap(:INT) {}
@@ -337,33 +347,37 @@ def maven_options(*options)
def mx(dir, *args)
command = ['mx', '-p', dir]
command.push *['--java-home', ENV['JVMCI_JAVA_HOME']] if ENV['JVMCI_JAVA_HOME']
command.push '-v'
command.push *args
sh *command
end

def mx_sulong(*args)
abort "You need to set SULONG_HOME" unless SULONG_HOME
mx SULONG_HOME, *args
end

def clang(*args)
if ENV['USE_SYSTEM_CLANG']
sh 'clang', *args
else
mx SULONG_HOME, 'su-clang', *args
mx_sulong 'su-clang', *args
end
end

def llvm_opt(*args)
if ENV['USE_SYSTEM_CLANG']
sh 'opt', *args
else
mx SULONG_HOME, 'su-opt', *args
mx_sulong 'su-opt', *args
end
end

def sulong_run(*args)
mx SULONG_HOME, 'su-run', *args
mx_sulong 'su-run', *args
end

def sulong_link(*args)
mx SULONG_HOME, 'su-link', *args
mx_sulong 'su-link', *args
end

def mspec(command, *args)
@@ -379,6 +393,11 @@ def mspec(command, *args)

sh env_vars, Utilities.find_ruby, 'spec/mspec/bin/mspec', command, '--config', 'spec/truffle/truffle.mspec', *args
end

def newer?(input, output)
return true unless File.exist? output
File.mtime(input) > File.mtime(output)
end
end

module Commands
@@ -390,7 +409,7 @@ def help
puts 'jt build [options] build'
puts 'jt rebuild [options] clean and build'
puts ' truffle build only the Truffle part, assumes the rest is up-to-date'
puts ' cexts build the cext backend (set SULONG_HOME and mabye USE_SYSTEM_CLANG)'
puts ' cexts [--no-openssl] build the cext backend (set SULONG_HOME and maybe USE_SYSTEM_CLANG)'
puts ' --offline use the build pack to build offline'
puts 'jt clean clean'
puts 'jt irb irb'
@@ -423,7 +442,7 @@ def help
puts 'jt test gems tests using gems'
puts 'jt test ecosystem [--offline] tests using the wider ecosystem such as bundler, Rails, etc'
puts ' (when --offline it will not use rubygems.org)'
puts 'jt test cexts run C extension tests'
puts 'jt test cexts [--no-libxml --no-openssl] run C extension tests'
puts ' (implies --graal, where Graal needs to include Sulong, set SULONG_HOME to a built checkout of Sulong, and set GEM_HOME)'
puts 'jt test report :language build a report on language specs'
puts ' :core (results go into test/target/mspec-html-report)'
@@ -459,8 +478,8 @@ def help
puts ' USE_SYSTEM_CLANG Use the system clang rather than Sulong\'s when compiling C extensions'
puts ' GRAAL_JS_JAR The location of trufflejs.jar'
puts ' SL_JAR The location of truffle-sl.jar'
puts ' OPENSSL_HOME The location of OpenSSL (the directory containing include etc)'
puts ' LIBXML_HOME The location of libxml2 (the directory containing include etc)'
puts ' LIBXML_HOME, LIBXML_INCLUDE, LIBXML_LIB The location of libxml2 (the directory containing include etc), and the direct include directory and library file'
puts ' OPENSSL_HOME, OPENSSL_INCLUDE, OPENSSL_LIB ... OpenSSL ...'
end

def checkout(branch)
@@ -481,14 +500,17 @@ def build(*options)
when 'truffle'
mvn env, *maven_options, '-pl', 'truffle', 'package'
when 'cexts'
no_openssl = options.delete('--no-openssl')

cextc "#{JRUBY_DIR}/truffle/src/main/c/cext"

openssl_home = ENV['OPENSSL_HOME'] || '/usr'

#cextc "#{JRUBY_DIR}/truffle/src/main/c/openssl",
# "-I#{openssl_home}/include",
# '-DRUBY_EXTCONF_H="extconf.h"',
# '-Werror=implicit-function-declaration'
unless no_openssl
cextc "#{JRUBY_DIR}/truffle/src/main/c/openssl",
'-DRUBY_EXTCONF_H="extconf.h"',
'-Werror=implicit-function-declaration'
end
when nil
mvn env, *maven_options, 'package'
else
@@ -599,14 +621,25 @@ def command_p(*args)
end

def cextc(cext_dir, *clang_opts)
abort "You need to set SULONG_HOME" unless SULONG_HOME

# Ensure ruby.su is up-to-date
ruby_cext_api = "#{JRUBY_DIR}/truffle/src/main/c/cext"
ruby_c = "#{JRUBY_DIR}/truffle/src/main/c/cext/ruby.c"
ruby_h = "#{JRUBY_DIR}/lib/ruby/truffle/cext/ruby.h"
ruby_su = "#{JRUBY_DIR}/lib/ruby/truffle/cext/ruby.su"
if cext_dir != ruby_cext_api and (newer?(ruby_h, ruby_su) or newer?(ruby_c, ruby_su))
puts "Compiling outdated ruby.su"
cextc ruby_cext_api
end

config_file = File.join(cext_dir, '.jruby-cext-build.yml')

unless File.exist?(config_file)
abort "There is no .jruby-cext-build.yml in #{cext_dir} at the moment - I don't know how to build it"
end

config = YAML.load_file(config_file)

config_src = config['src']

if config_src.start_with?('$GEM_HOME/')
@@ -639,11 +672,15 @@ def cextc(cext_dir, *clang_opts)

if MAC
config_libs.each do |lib|
lib['.so'] = '.dylib'
if lib.include?('.so')
lib['.so'] = '.dylib'
end
end
end

sulong_link '-o', out, *((config_libs.map { |l| ['-l', l] }).flatten), *lls
config_libs = config_libs.flat_map { |l| ['-l', l] }

sulong_link '-o', out, *config_libs, *lls
end

def test(*args)
@@ -727,37 +764,44 @@ def test_compiler(*args)
private :test_compiler

def test_cexts(*args)
if MAC
so = 'dylib'
else
so = 'so'
end
no_libxml = args.delete('--no-libxml')
no_openssl = args.delete('--no-openssl')

# Test that we can compile and run some basic C code that uses libxml and openssl

clang '-S', '-emit-llvm', "-I#{LIBXML_HOME}/include/libxml2", 'test/truffle/cexts/xml/main.c', '-o', 'test/truffle/cexts/xml/main.ll'
out, _ = sulong_run("-l#{LIBXML_LIB_HOME}/libxml2.#{so}", 'test/truffle/cexts/xml/main.ll', {capture: true})
raise unless out == "7\n"
unless no_libxml
clang '-S', '-emit-llvm', "-I#{LIBXML_INCLUDE}", 'test/truffle/cexts/xml/main.c', '-o', 'test/truffle/cexts/xml/main.ll'
out, _ = sulong_run("-l#{LIBXML_LIB}", 'test/truffle/cexts/xml/main.ll', {capture: true})
raise unless out == "7\n"
end

clang '-S', '-emit-llvm', "-I#{OPENSSL_HOME}/include", 'test/truffle/cexts/xopenssl/main.c', '-o', 'test/truffle/cexts/xopenssl/main.ll'
out, _ = sulong_run("-l#{OPENSSL_LIB_HOME}/libssl.#{so}", 'test/truffle/cexts/xopenssl/main.ll', {capture: true})
raise unless out == "5d41402abc4b2a76b9719d911017c592\n"
unless no_openssl
clang '-S', '-emit-llvm', "-I#{OPENSSL_INCLUDE}", 'test/truffle/cexts/xopenssl/main.c', '-o', 'test/truffle/cexts/xopenssl/main.ll'
out, _ = sulong_run("-l#{OPENSSL_LIB}", 'test/truffle/cexts/xopenssl/main.ll', {capture: true})
raise unless out == "5d41402abc4b2a76b9719d911017c592\n"
end

# Test that we can run those same test when they're build as a .su and we load the code and libraries from that

sulong_link '-o', 'test/truffle/cexts/xml/main.su', '-l', "#{LIBXML_LIB_HOME}/libxml2.#{so}", 'test/truffle/cexts/xml/main.ll'
out, _ = sulong_run('test/truffle/cexts/xml/main.su', {capture: true})
raise unless out == "7\n"
unless no_libxml
sulong_link '-o', 'test/truffle/cexts/xml/main.su', '-l', "#{LIBXML_LIB}", 'test/truffle/cexts/xml/main.ll'
out, _ = sulong_run('test/truffle/cexts/xml/main.su', {capture: true})
raise unless out == "7\n"
end

sulong_link '-o', 'test/truffle/cexts/xopenssl/main.su', '-l', "#{OPENSSL_LIB_HOME}/libssl.#{so}", 'test/truffle/cexts/xopenssl/main.ll'
out, _ = sulong_run('test/truffle/cexts/xopenssl/main.su', {capture: true})
raise unless out == "5d41402abc4b2a76b9719d911017c592\n"
unless no_openssl
sulong_link '-o', 'test/truffle/cexts/xopenssl/main.su', '-l', "#{OPENSSL_LIB}", 'test/truffle/cexts/xopenssl/main.ll'
out, _ = sulong_run('test/truffle/cexts/xopenssl/main.su', {capture: true})
raise unless out == "5d41402abc4b2a76b9719d911017c592\n"
end

# Test that we can compile and run some very basic C extensions

begin
output_file = 'cext-output.txt'
['minimum', 'method', 'module', 'globals', 'xml', 'xopenssl'].each do |gem_name|
next if gem_name == 'xml' && no_libxml
next if gem_name == 'xopenssl' && no_openssl
dir = "#{JRUBY_DIR}/test/truffle/cexts/#{gem_name}"
cextc dir
name = File.basename(dir)
@@ -779,6 +823,7 @@ def test_cexts(*args)
['nokogiri', [], ['nokogiri']]
].each do |gem_name, dependencies, libs|
next if gem_name == 'nokogiri' # nokogiri totally excluded
next if gem_name == 'nokogiri' && no_libxml
config = "#{JRUBY_DIR}/test/truffle/cexts/#{gem_name}"
cextc config, '-Werror=implicit-function-declaration'
next if gem_name == 'psd_native' # psd_native is excluded just for running
@@ -1189,7 +1234,7 @@ def main(args)
send(args.shift)
when "build"
command = [args.shift]
while ['truffle', 'cexts', '--offline'].include?(args.first)
while ['truffle', 'cexts', '--offline', '--no-openssl'].include?(args.first)
command << args.shift
end
send(*command)
7 changes: 3 additions & 4 deletions tool/truffle/callgraph2html.rb
Original file line number Diff line number Diff line change
@@ -136,7 +136,6 @@ def reachable
method_version = objects[Integer(line[1])]
eval_code = line.drop(2).join(' ')
method_version.eval_code.push eval_code
when 'local'
when 'callsite'
method = objects[Integer(line[1])]
callsite = CG::CallSite.new(line[2], method, line[3])
@@ -245,15 +244,15 @@ def annotate(method_version, offset)
<% if reachable_objects.include?(method_version) %>
<div id='method-version-<%= method_version.id %>' class='method-version'>
<% unless method_version.called_from.empty? %>
<p>Called from:</p>
<p>Called from:</p>
<ul>
<% method_version.called_from.each do |caller| %>
<li><a href='#method-version-<%= caller.method_version.id %>'><%= h(caller.method_version.method.name) %></a></li>
<% end %>
</ul>
<% end %>
<% unless method_version.locals.empty? %>
<p>Locals:</p>
<p>Locals:</p>
<ul>
<% method_version.locals.each do |name, types| %>
<li><code><%= h(name) %></li>
@@ -266,7 +265,7 @@ def annotate(method_version, offset)
</ul>
<% end %>
<% unless method_version.eval_code.empty? %>
<p>Evals:</p>
<p>Evals:</p>
<ul>
<% method_version.eval_code.each do |eval_code| %>
<li><code><%= h(eval_code) %></code></li>
626 changes: 569 additions & 57 deletions truffle/src/main/c/cext/ruby.c

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions truffle/src/main/c/openssl/.jruby-cext-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
src: ./*.c
cflags: -I$OPENSSL_HOME/include
libs: $OPENSSL_LIB_HOME/libssl.so
cflags: -I$OPENSSL_INCLUDE
libs: $OPENSSL_LIB
out: ../../../../../lib/ruby/truffle/openssl/openssl.su
6 changes: 6 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/Layouts.java
Original file line number Diff line number Diff line change
@@ -26,6 +26,10 @@
import org.jruby.truffle.core.encoding.EncodingLayoutImpl;
import org.jruby.truffle.core.exception.ExceptionLayout;
import org.jruby.truffle.core.exception.ExceptionLayoutImpl;
import org.jruby.truffle.core.exception.NameErrorLayout;
import org.jruby.truffle.core.exception.NameErrorLayoutImpl;
import org.jruby.truffle.core.exception.NoMethodErrorLayout;
import org.jruby.truffle.core.exception.NoMethodErrorLayoutImpl;
import org.jruby.truffle.core.exception.SystemCallErrorLayout;
import org.jruby.truffle.core.exception.SystemCallErrorLayoutImpl;
import org.jruby.truffle.core.fiber.FiberLayout;
@@ -121,6 +125,8 @@ public abstract class Layouts {
public static final MethodLayout METHOD = MethodLayoutImpl.INSTANCE;
public static final ModuleLayout MODULE = ModuleLayoutImpl.INSTANCE;
public static final MutexLayout MUTEX = MutexLayoutImpl.INSTANCE;
public static final NameErrorLayout NAME_ERROR = NameErrorLayoutImpl.INSTANCE;
public static final NoMethodErrorLayout NO_METHOD_ERROR = NoMethodErrorLayoutImpl.INSTANCE;
public static final ObjectRangeLayout OBJECT_RANGE = ObjectRangeLayoutImpl.INSTANCE;
public static final PointerLayout POINTER = PointerLayoutImpl.INSTANCE;
public static final ProcLayout PROC = ProcLayoutImpl.INSTANCE;
8 changes: 8 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -44,6 +44,8 @@
import org.jruby.truffle.core.encoding.EncodingConverterNodesFactory;
import org.jruby.truffle.core.encoding.EncodingNodesFactory;
import org.jruby.truffle.core.exception.ExceptionNodesFactory;
import org.jruby.truffle.core.exception.NameErrorNodesFactory;
import org.jruby.truffle.core.exception.NoMethodErrorNodesFactory;
import org.jruby.truffle.core.exception.SystemCallErrorNodesFactory;
import org.jruby.truffle.core.fiber.FiberNodesFactory;
import org.jruby.truffle.core.hash.HashNodesFactory;
@@ -394,7 +396,9 @@ public CoreLibrary(RubyContext context) {

// StandardError > NameError
nameErrorClass = defineClass(standardErrorClass, "NameError");
Layouts.CLASS.setInstanceFactoryUnsafe(nameErrorClass, Layouts.NAME_ERROR.createNameErrorShape(nameErrorClass, nameErrorClass));
noMethodErrorClass = defineClass(nameErrorClass, "NoMethodError");
Layouts.CLASS.setInstanceFactoryUnsafe(noMethodErrorClass, Layouts.NO_METHOD_ERROR.createNoMethodErrorShape(noMethodErrorClass, noMethodErrorClass));

// StandardError > SystemCallError
systemCallErrorClass = defineClass(standardErrorClass, "SystemCallError");
@@ -676,6 +680,8 @@ public void addPrimitives() {
primitiveManager.addPrimitiveNodes(IOPrimitiveNodesFactory.getFactories());
primitiveManager.addPrimitiveNodes(IOBufferPrimitiveNodesFactory.getFactories());
primitiveManager.addPrimitiveNodes(ExceptionNodesFactory.getFactories());
primitiveManager.addPrimitiveNodes(NameErrorNodesFactory.getFactories());
primitiveManager.addPrimitiveNodes(NoMethodErrorNodesFactory.getFactories());
primitiveManager.addPrimitiveNodes(SystemCallErrorNodesFactory.getFactories());
return null;
}, () -> {
@@ -705,6 +711,8 @@ public void addCoreMethods() {
coreMethodNodeManager.addCoreMethodNodes(ClassNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(ConditionVariableNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(ExceptionNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(NameErrorNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(NoMethodErrorNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(SystemCallErrorNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(FalseClassNodesFactory.getFactories());
return null;
Original file line number Diff line number Diff line change
@@ -280,13 +280,13 @@ private DynamicObject buildMethodMissingException(Object self, DynamicObject nam
final String name = nameObject.toString();

if (lastCallWasSuper()) {
return coreExceptions().noSuperMethodError(name, this);
return coreExceptions().noSuperMethodError(name, self, args, this);
} else if (lastCallWasCallingPrivateMethod(self, name)) {
return coreExceptions().privateMethodError(name, self, this);
return coreExceptions().privateMethodError(name, self, args, this);
} else if (lastCallWasVCall()) {
return coreExceptions().nameErrorUndefinedLocalVariableOrMethod(name, self, this);
} else {
return coreExceptions().noMethodErrorOnReceiver(name, self, this);
return coreExceptions().noMethodErrorOnReceiver(name, self, args, this);
}
}

Original file line number Diff line number Diff line change
@@ -392,7 +392,8 @@ public Object encodingConverterLastError(VirtualFrame frame, DynamicObject encod
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("result"), eConvResultToSymbol(lastError.getResult()));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("source_encoding_name"), createString(new ByteList(lastError.getSource())));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("destination_encoding_name"), createString(new ByteList(lastError.getDestination())));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("error_bytes"), createString(new ByteList(lastError.getErrorBytes())));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("error_bytes"), createString(new ByteList(lastError.getErrorBytes(),
lastError.getErrorBytesP(), lastError.getErrorBytesP() + lastError.getErrorBytesLength())));

if (lastError.getReadAgainLength() != 0) {
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("read_again_bytes"), createString(new ByteList(lastError.getErrorBytes(),
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;

import static org.jruby.truffle.core.array.ArrayHelpers.createArray;

public class CoreExceptions {

private final RubyContext context;
@@ -120,6 +122,11 @@ public DynamicObject argumentErrorInvalidValue(Object object, String expectedTyp
return argumentError(String.format("invalid value for %s(): %s", badClassName, expectedType), currentNode);
}

@TruffleBoundary
public DynamicObject argumentErrorNoReceiver(Node currentNode) {
return argumentError("no receiver is available", currentNode);
}

@TruffleBoundary
public DynamicObject argumentError(String message, Node currentNode, Throwable javaThrowable) {
return argumentError(StringOperations.encodeRope(message, UTF8Encoding.INSTANCE), currentNode, javaThrowable);
@@ -406,7 +413,7 @@ public DynamicObject typeError(String message, Node currentNode, Throwable javaT

@TruffleBoundary
public DynamicObject nameErrorConstantNotDefined(DynamicObject module, String name, Node currentNode) {
return nameError(String.format("constant %s::%s not defined", Layouts.MODULE.getFields(module).getName(), name), name, currentNode);
return nameError(String.format("constant %s::%s not defined", Layouts.MODULE.getFields(module).getName(), name), null, name, currentNode);
}

@TruffleBoundary
@@ -418,121 +425,122 @@ public DynamicObject nameErrorUninitializedConstant(DynamicObject module, String
} else {
message = String.format("uninitialized constant %s::%s", Layouts.MODULE.getFields(module).getName(), name);
}
return nameError(message, name, currentNode);
return nameError(message, module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorUninitializedClassVariable(DynamicObject module, String name, Node currentNode) {
assert RubyGuards.isRubyModule(module);
return nameError(String.format("uninitialized class variable %s in %s", name, Layouts.MODULE.getFields(module).getName()), name, currentNode);
return nameError(String.format("uninitialized class variable %s in %s", name, Layouts.MODULE.getFields(module).getName()), module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorPrivateConstant(DynamicObject module, String name, Node currentNode) {
return nameError(String.format("private constant %s::%s referenced", Layouts.MODULE.getFields(module).getName(), name), name, currentNode);
return nameError(String.format("private constant %s::%s referenced", Layouts.MODULE.getFields(module).getName(), name), module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorInstanceNameNotAllowable(String name, Node currentNode) {
return nameError(String.format("`%s' is not allowable as an instance variable name", name), name, currentNode);
public DynamicObject nameErrorInstanceNameNotAllowable(String name, Object receiver, Node currentNode) {
return nameError(String.format("`%s' is not allowable as an instance variable name", name), receiver, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorInstanceVariableNotDefined(String name, Node currentNode) {
return nameError(String.format("instance variable %s not defined", name), name, currentNode);
public DynamicObject nameErrorInstanceVariableNotDefined(String name, Object receiver, Node currentNode) {
return nameError(String.format("instance variable %s not defined", name), receiver, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorReadOnly(String name, Node currentNode) {
return nameError(String.format("%s is a read-only variable", name), name, currentNode);
return nameError(String.format("%s is a read-only variable", name), null, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorUndefinedLocalVariableOrMethod(String name, Object receiver, Node currentNode) {
// TODO: should not be just the class, but rather sth like name_err_mesg_to_str() in MRI error.c
String className = Layouts.MODULE.getFields(context.getCoreLibrary().getLogicalClass(receiver)).getName();
return nameError(String.format("undefined local variable or method `%s' for %s", name, className), name, currentNode);
return nameError(String.format("undefined local variable or method `%s' for %s", name, className), receiver, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorUndefinedMethod(String name, DynamicObject module, Node currentNode) {
assert RubyGuards.isRubyModule(module);
return nameError(String.format("undefined method `%s' for %s", name, Layouts.MODULE.getFields(module).getName()), name, currentNode);
return nameError(String.format("undefined method `%s' for %s", name, Layouts.MODULE.getFields(module).getName()), module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorMethodNotDefinedIn(DynamicObject module, String name, Node currentNode) {
return nameError(String.format("method `%s' not defined in %s", name, Layouts.MODULE.getFields(module).getName()), name, currentNode);
return nameError(String.format("method `%s' not defined in %s", name, Layouts.MODULE.getFields(module).getName()), module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorPrivateMethod(String name, DynamicObject module, Node currentNode) {
return nameError(String.format("method `%s' for %s is private", name, Layouts.MODULE.getFields(module).getName()), name, currentNode);
return nameError(String.format("method `%s' for %s is private", name, Layouts.MODULE.getFields(module).getName()), module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorLocalVariableNotDefined(String name, DynamicObject binding, Node currentNode) {
assert RubyGuards.isRubyBinding(binding);
return nameError(String.format("local variable `%s' not defined for %s", name, binding.toString()), name, currentNode);
return nameError(String.format("local variable `%s' not defined for %s", name, binding.toString()), binding, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorClassVariableNotDefined(String name, DynamicObject module, Node currentNode) {
assert RubyGuards.isRubyModule(module);
return nameError(String.format("class variable `%s' not defined for %s", name, Layouts.MODULE.getFields(module).getName()), name, currentNode);
return nameError(String.format("class variable `%s' not defined for %s", name, Layouts.MODULE.getFields(module).getName()), module, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameErrorImportNotFound(String name, Node currentNode) {
return nameError(String.format("import '%s' not found", name), name, currentNode);
return nameError(String.format("import '%s' not found", name), null, name, currentNode);
}

@TruffleBoundary
public DynamicObject nameError(String message, String name, Node currentNode) {
public DynamicObject nameError(String message, Object receiver, String name, Node currentNode) {
final DynamicObject nameString = StringOperations.createString(context, StringOperations.encodeRope(message, UTF8Encoding.INSTANCE));
DynamicObject nameError = ExceptionOperations.createRubyException(context.getCoreLibrary().getNameErrorClass(), nameString, context.getCallStack().getBacktrace(currentNode));
nameError.define("@name", context.getSymbolTable().getSymbol(name), 0);
DynamicObject nameError = ExceptionOperations.createNameError(context.getCoreLibrary().getNameErrorClass(), nameString, context.getCallStack().getBacktrace(currentNode), receiver, context.getSymbolTable().getSymbol(name));
return nameError;
}

// NoMethodError

@TruffleBoundary
public DynamicObject noMethodError(String message, String name, Node currentNode) {
public DynamicObject noMethodError(String message, Object receiver, String name, Object[] args, Node currentNode) {
final DynamicObject messageString = StringOperations.createString(context, StringOperations.encodeRope(message, UTF8Encoding.INSTANCE));
DynamicObject noMethodError = ExceptionOperations.createRubyException(context.getCoreLibrary().getNoMethodErrorClass(), messageString, context.getCallStack().getBacktrace(currentNode));
noMethodError.define("@name", context.getSymbolTable().getSymbol(name), 0);
final DynamicObject argsArray = createArray(context, args, args.length);
final DynamicObject noMethodError = ExceptionOperations.createNoMethodError(context.getCoreLibrary().getNoMethodErrorClass(), messageString, context.getCallStack().getBacktrace(currentNode), receiver, context.getSymbolTable().getSymbol(name), argsArray);
return noMethodError;
}

@TruffleBoundary
public DynamicObject noSuperMethodOutsideMethodError(Node currentNode) {
DynamicObject noMethodError = noMethodError("super called outside of method", "<unknown>", currentNode);
noMethodError.define("@name", context.getCoreLibrary().getNilObject(), 0); // FIXME: the name of the method is not known in this case currently
final DynamicObject messageString = StringOperations.createString(context, StringOperations.encodeRope("super called outside of method", UTF8Encoding.INSTANCE));
// TODO BJF Jul 21, 2016 Review to add receiver
DynamicObject noMethodError = ExceptionOperations.createNameError(context.getCoreLibrary().getNoMethodErrorClass(), messageString, context.getCallStack().getBacktrace(currentNode), null, context.getSymbolTable().getSymbol("<unknown>"));
// FIXME: the name of the method is not known in this case currently
return noMethodError;
}

@TruffleBoundary
public DynamicObject noSuperMethodError(String name, Node currentNode) {
return noMethodError(String.format("super: no superclass method `%s'", name), name, currentNode);
public DynamicObject noSuperMethodError(String name, Object self, Object[] args, Node currentNode) {
return noMethodError(String.format("super: no superclass method `%s'", name), self, name, args, currentNode);
}

@TruffleBoundary
public DynamicObject noMethodErrorOnReceiver(String name, Object receiver, Node currentNode) {
public DynamicObject noMethodErrorOnReceiver(String name, Object receiver, Object[] args, Node currentNode) {
final DynamicObject logicalClass = context.getCoreLibrary().getLogicalClass(receiver);
final String moduleName = Layouts.MODULE.getFields(logicalClass).getName();

// e.g. BasicObject does not have inspect
final boolean hasInspect = ModuleOperations.lookupMethod(logicalClass, "inspect", Visibility.PUBLIC) != null;
final Object stringRepresentation = hasInspect ? context.send(receiver, "inspect", null) : context.getCoreLibrary().getNilObject();

return noMethodError(String.format("undefined method `%s' for %s:%s", name, stringRepresentation, moduleName), name, currentNode);
return noMethodError(String.format("undefined method `%s' for %s:%s", name, stringRepresentation, moduleName), receiver, name, args, currentNode);
}

@TruffleBoundary
public DynamicObject privateMethodError(String name, Object self, Node currentNode) {
public DynamicObject privateMethodError(String name, Object self, Object[] args, Node currentNode) {
String className = Layouts.MODULE.getFields(context.getCoreLibrary().getLogicalClass(self)).getName();
return noMethodError(String.format("private method `%s' called for %s", name, className), name, currentNode);
return noMethodError(String.format("private method `%s' called for %s", name, className), self, name, args, currentNode);
}

// LoadError
@@ -647,6 +655,21 @@ public DynamicObject rangeError(DynamicObject range, Node currentNode) {
Layouts.INT_RANGE.getEnd(range)), currentNode);
}

@TruffleBoundary
public DynamicObject rangeErrorConvertToInt(long value, Node currentNode) {
final String direction;

if (value < Integer.MIN_VALUE) {
direction = "small";
} else if (value > Integer.MAX_VALUE) {
direction = "big";
} else {
throw new IllegalArgumentException();
}

return rangeError(String.format("integer %d too %s to convert to `int'", value, direction), currentNode);
}

@TruffleBoundary
public DynamicObject rangeError(String message, Node currentNode) {
return ExceptionOperations.createRubyException(
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.ConditionProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
@@ -25,7 +24,6 @@
import org.jruby.truffle.builtins.NonStandard;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.backtrace.Backtrace;
@@ -37,6 +35,23 @@
@CoreClass("Exception")
public abstract class ExceptionNodes {

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocateNameError(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, nil(), null);
}

}

@CoreMethod(names = "initialize", optional = 1)
public abstract static class InitializeNode extends CoreMethodArrayArgumentsNode {

@@ -81,9 +96,7 @@ public Object backtrace(
private ReadObjectFieldNode getReadCustomBacktraceNode() {
if (readCustomBacktraceNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
readCustomBacktraceNode = insert(ReadObjectFieldNodeGen.create(
"@custom_backtrace",
null));
readCustomBacktraceNode = insert(ReadObjectFieldNodeGen.create("@custom_backtrace", null));
}

return readCustomBacktraceNode;
@@ -123,23 +136,6 @@ public Object message(DynamicObject exception) {

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, nil(), null, nil());
}

}

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

Original file line number Diff line number Diff line change
@@ -50,4 +50,12 @@ public static DynamicObject createSystemCallError(DynamicObject rubyClass, Objec
return Layouts.SYSTEM_CALL_ERROR.createSystemCallError(Layouts.CLASS.getInstanceFactory(rubyClass), message, backtrace, errno);
}

public static DynamicObject createNameError(DynamicObject rubyClass, Object message, Backtrace backtrace, Object receiver, Object name) {
return Layouts.NAME_ERROR.createNameError(Layouts.CLASS.getInstanceFactory(rubyClass), message, backtrace, receiver, name);
}

public static DynamicObject createNoMethodError(DynamicObject rubyClass, Object message, Backtrace backtrace, Object receiver, Object name, DynamicObject args) {
return Layouts.NO_METHOD_ERROR.createNoMethodError(Layouts.CLASS.getInstanceFactory(rubyClass), message, backtrace, receiver, name, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core.exception;

import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
import com.oracle.truffle.api.object.dsl.Layout;
import com.oracle.truffle.api.object.dsl.Nullable;
import org.jruby.truffle.language.backtrace.Backtrace;

@Layout
public interface NameErrorLayout extends ExceptionLayout {

DynamicObjectFactory createNameErrorShape(
DynamicObject logicalClass,
DynamicObject metaClass);

DynamicObject createNameError(
DynamicObjectFactory factory,
Object message,
@Nullable Backtrace backtrace,
@Nullable Object receiver,
Object name);

Object getName(DynamicObject object);
void setName(DynamicObject object, Object value);

Object getReceiver(DynamicObject object);
void setReceiver(DynamicObject object, Object value);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core.exception;

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;

@CoreClass("NameError")
public abstract class NameErrorNodes {

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocateNameError(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, nil(), null, null, nil());
}

}

@CoreMethod(names = "name")
public abstract static class NameNode extends CoreMethodArrayArgumentsNode {

@Specialization
public Object name(DynamicObject self) {
return Layouts.NAME_ERROR.getName(self);
}

}

@CoreMethod(names = "receiver")
public abstract static class ReceiverNode extends CoreMethodArrayArgumentsNode {

@Specialization
public Object receiver(DynamicObject self) {
final Object receiver = Layouts.NAME_ERROR.getReceiver(self);

// TODO BJF July 21, 2016 Implement name error in message field

if (receiver == null) {
throw new RaiseException(coreExceptions().argumentErrorNoReceiver(this));
}
return receiver;
}

}

@Primitive(name = "name_error_set_name")
public abstract static class NameSetNode extends PrimitiveArrayArgumentsNode {

@Specialization
public Object setName(DynamicObject error, Object name) {
Layouts.NAME_ERROR.setName(error, name);
return name;
}

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core.exception;

import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
import com.oracle.truffle.api.object.dsl.Layout;
import com.oracle.truffle.api.object.dsl.Nullable;
import org.jruby.truffle.language.backtrace.Backtrace;

@Layout
public interface NoMethodErrorLayout extends NameErrorLayout {

DynamicObjectFactory createNoMethodErrorShape(
DynamicObject logicalClass,
DynamicObject metaClass);

DynamicObject createNoMethodError(
DynamicObjectFactory factory,
Object message,
@Nullable Backtrace backtrace,
@Nullable Object receiver,
Object name,
Object args);

Object getArgs(DynamicObject object);
void setArgs(DynamicObject object, Object value);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core.exception;

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;

@CoreClass("NoMethodError")
public abstract class NoMethodErrorNodes {

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocateNoMethodError(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, nil(), null, null, nil(), nil());
}

}

@CoreMethod(names = "args")
public abstract static class ArgsNode extends CoreMethodArrayArgumentsNode {

@Specialization
public Object args(DynamicObject self) {
return Layouts.NO_METHOD_ERROR.getArgs(self);
}

}

@Primitive(name = "no_method_error_set_args")
public abstract static class ArgsSetNode extends PrimitiveArrayArgumentsNode {

@Specialization
public Object setArgs(DynamicObject error, Object args) {
Layouts.NO_METHOD_ERROR.setArgs(error, args);
return args;
}

}


}
Original file line number Diff line number Diff line change
@@ -2,16 +2,37 @@

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;

@CoreClass("SystemCallError")
public abstract class SystemCallErrorNodes {

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocateNameError(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, nil(), null, nil());
}

}

@CoreMethod(names = "errno")
public abstract static class ErrnoNode extends CoreMethodArrayArgumentsNode {

Original file line number Diff line number Diff line change
@@ -468,7 +468,6 @@ public abstract static class DupNode extends CoreMethodArrayArgumentsNode {

@Child private CopyNode copyNode;
@Child private CallDispatchHeadNode initializeDupNode;
@Child private SingletonClassNode singletonClassNode;

public DupNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
@@ -477,7 +476,7 @@ public DupNode(RubyContext context, SourceSection sourceSection) {
initializeDupNode = DispatchHeadNodeFactory.createMethodCallOnSelf(context);
}

@Specialization(guards = "!isRubyClass(self)")
@Specialization
public DynamicObject dup(VirtualFrame frame, DynamicObject self) {
final DynamicObject newObject = copyNode.executeCopy(frame, self);

@@ -486,27 +485,6 @@ public DynamicObject dup(VirtualFrame frame, DynamicObject self) {
return newObject;
}

@Specialization(guards = "isRubyClass(self)")
public DynamicObject dupClass(VirtualFrame frame, DynamicObject self) {
if (singletonClassNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
singletonClassNode = insert(SingletonClassNodeGen.create(getContext(), getSourceSection(), null));
}

final DynamicObject newObject = copyNode.executeCopy(frame, self);
final DynamicObject newObjectMetaClass = singletonClassNode.executeSingletonClass(newObject);
final DynamicObject selfMetaClass = Layouts.BASIC_OBJECT.getMetaClass(self);

assert Layouts.CLASS.getIsSingleton(selfMetaClass);
assert Layouts.CLASS.getIsSingleton(Layouts.BASIC_OBJECT.getMetaClass(newObject));

Layouts.MODULE.getFields(newObjectMetaClass).initCopy(selfMetaClass); // copies class methods
initializeDupNode.call(frame, newObject, "initialize_dup", self);
Layouts.CLASS.setSuperclass(newObject, Layouts.CLASS.getSuperclass(self));

return newObject;
}

}

@CoreMethod(names = "eval", isModuleFunction = true, required = 1, optional = 3, lowerFixnum = 4)
@@ -975,7 +953,7 @@ public RubyNode coerceToString(RubyNode name) {
@TruffleBoundary
@Specialization
public boolean isInstanceVariableDefined(DynamicObject object, String name) {
final String ivar = SymbolTable.checkInstanceVariableName(getContext(), name, this);
final String ivar = SymbolTable.checkInstanceVariableName(getContext(), name, object, this);
return object.getShape().hasProperty(ivar);
}

@@ -1045,10 +1023,10 @@ public RubyNode coerceToString(RubyNode name) {
@TruffleBoundary
@Specialization
public Object removeInstanceVariable(DynamicObject object, String name) {
final String ivar = SymbolTable.checkInstanceVariableName(getContext(), name, this);
final String ivar = SymbolTable.checkInstanceVariableName(getContext(), name, object, this);
final Object value = object.get(ivar, nil());
if (!object.delete(name)) {
throw new RaiseException(coreExceptions().nameErrorInstanceVariableNotDefined(name, this));
throw new RaiseException(coreExceptions().nameErrorInstanceVariableNotDefined(name, object, this));
}
return value;
}
Original file line number Diff line number Diff line change
@@ -522,7 +522,7 @@ public AutoloadNode(RubyContext context, SourceSection sourceSection) {
@Specialization(guards = "isRubyString(filename)")
public DynamicObject autoload(DynamicObject module, String name, DynamicObject filename) {
if (!IdUtil.isValidConstantName19(name)) {
throw new RaiseException(coreExceptions().nameError(String.format("autoload must be constant name: %s", name), name, this));
throw new RaiseException(coreExceptions().nameError(String.format("autoload must be constant name: %s", name), module, name, this));
}

if (isEmptyNode.executeIsEmpty(filename)) {
@@ -686,7 +686,7 @@ public RubyNode coerceToString(RubyNode name) {
@TruffleBoundary(throwsControlFlowException = true)
@Specialization
public boolean isClassVariableDefinedString(DynamicObject module, String name) {
SymbolTable.checkClassVariableName(getContext(), name, this);
SymbolTable.checkClassVariableName(getContext(), name, module, this);

final Object value = ModuleOperations.lookupClassVariable(module, name);

@@ -710,7 +710,7 @@ public RubyNode coerceToString(RubyNode name) {
@Specialization
@TruffleBoundary(throwsControlFlowException = true)
public Object getClassVariable(DynamicObject module, String name) {
SymbolTable.checkClassVariableName(getContext(), name, this);
SymbolTable.checkClassVariableName(getContext(), name, module, this);

final Object value = ModuleOperations.lookupClassVariable(module, name);

@@ -739,7 +739,7 @@ public RubyNode coerceToString(RubyNode name) {
@Specialization
@TruffleBoundary(throwsControlFlowException = true)
public Object setClassVariable(DynamicObject module, String name, Object value) {
SymbolTable.checkClassVariableName(getContext(), name, this);
SymbolTable.checkClassVariableName(getContext(), name, module, this);

ModuleOperations.setClassVariable(getContext(), module, name, value, this);

@@ -964,7 +964,7 @@ public RubyNode coerceToString(RubyNode name) {
@Specialization
public Object setConstant(DynamicObject module, String name, Object value) {
if (!IdUtil.isValidConstantName19(name)) {
throw new RaiseException(coreExceptions().nameError(String.format("wrong constant name %s", name), name, this));
throw new RaiseException(coreExceptions().nameError(String.format("wrong constant name %s", name), module, name, this));
}

Layouts.MODULE.getFields(module).setConstant(getContext(), this, name, value);
@@ -1150,14 +1150,16 @@ public DynamicObject initialize(VirtualFrame frame, DynamicObject module, Dynami
@CoreMethod(names = "initialize_copy", required = 1)
public abstract static class InitializeCopyNode extends CoreMethodArrayArgumentsNode {

@Child private SingletonClassNode singletonClassNode;

@Specialization(guards = { "!isRubyClass(self)", "isRubyModule(from)", "!isRubyClass(from)" })
public Object initializeCopyModule(DynamicObject self, DynamicObject from) {
Layouts.MODULE.getFields(self).initCopy(from);
return nil();
}

@Specialization(guards = {"isRubyClass(self)", "isRubyClass(from)"})
public Object initializeCopy(DynamicObject self, DynamicObject from,
public Object initializeCopyClass(DynamicObject self, DynamicObject from,
@Cached("create()") BranchProfile errorProfile) {
if (from == coreLibrary().getBasicObjectClass()) {
errorProfile.enter();
@@ -1168,9 +1170,28 @@ public Object initializeCopy(DynamicObject self, DynamicObject from,
}

Layouts.MODULE.getFields(self).initCopy(from);

final DynamicObject selfMetaClass = getSingletonClass(self);
final DynamicObject fromMetaClass = Layouts.BASIC_OBJECT.getMetaClass(from);

assert Layouts.CLASS.getIsSingleton(fromMetaClass);
assert Layouts.CLASS.getIsSingleton(Layouts.BASIC_OBJECT.getMetaClass(self));

Layouts.MODULE.getFields(selfMetaClass).initCopy(fromMetaClass); // copy class methods
Layouts.CLASS.setSuperclass(self, Layouts.CLASS.getSuperclass(from));

return nil();
}

protected DynamicObject getSingletonClass(DynamicObject object) {
if (singletonClassNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
singletonClassNode = insert(SingletonClassNodeGen.create(getContext(), getSourceSection(), null));
}

return singletonClassNode.executeSingletonClass(object);
}

}

@CoreMethod(names = "included", required = 1, visibility = Visibility.PRIVATE)
@@ -1655,7 +1676,7 @@ public RubyNode coerceToString(RubyNode name) {
@TruffleBoundary(throwsControlFlowException = true)
@Specialization
public Object removeClassVariableString(DynamicObject module, String name) {
SymbolTable.checkClassVariableName(getContext(), name, this);
SymbolTable.checkClassVariableName(getContext(), name, module, this);
return ModuleOperations.removeClassVariable(Layouts.MODULE.getFields(module), getContext(), this, name);
}

Original file line number Diff line number Diff line change
@@ -183,7 +183,7 @@ public static RubyConstant lookupScopedConstant(RubyContext context, DynamicObje

final String lastSegment = fullName.substring(start);
if (!IdUtil.isValidConstantName19(lastSegment)) {
throw new RaiseException(context.getCoreExceptions().nameError(String.format("wrong constant name %s", fullName), fullName, currentNode));
throw new RaiseException(context.getCoreExceptions().nameError(String.format("wrong constant name %s", fullName), module, fullName, currentNode));
}

return lookupConstantWithInherit(context, module, lastSegment, inherit, currentNode);
@@ -194,7 +194,7 @@ public static RubyConstant lookupConstantWithInherit(RubyContext context, Dynami
assert RubyGuards.isRubyModule(module);

if (!IdUtil.isValidConstantName19(name)) {
throw new RaiseException(context.getCoreExceptions().nameError(String.format("wrong constant name %s", name), name, currentNode));
throw new RaiseException(context.getCoreExceptions().nameError(String.format("wrong constant name %s", name), module, name, currentNode));
}

if (inherit) {
Original file line number Diff line number Diff line change
@@ -80,28 +80,44 @@ public DynamicObject wait(DynamicObject conditionVariable, DynamicObject mutex,
}

@TruffleBoundary
private void doWait(final long durationInMillis, ReentrantLock lock, DynamicObject thread, Object condition) {
final long start = System.currentTimeMillis();
private void doWait(
final long durationInMillis,
ReentrantLock lock,
DynamicObject thread,
Object condition) {

// First lock the condition so we only release the Mutex when we are in wait() and ready to be notified
synchronized (condition) {
MutexOperations.unlock(lock, thread, this);
try {
getContext().getThreadManager().runUntilResult(this, new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
long now = System.currentTimeMillis();
long slept = now - start;

if (slept >= durationInMillis) {
return SUCCESS;
}

condition.wait(durationInMillis - slept);
return SUCCESS;
}
});
} finally {
final long start = System.currentTimeMillis();
boolean doLock = false;

try {
// First acquire the condition monitor, so we only release the Mutex
// when we own the condition monitor blocking notify/notifyAll calls until
// we are in wait(), ready to be notified.
synchronized (condition) {
MutexOperations.unlock(lock, thread, this);
// successfully unlocked, do lock later
doLock = true;
getContext().getThreadManager().
runUntilResult(this, new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
long now = System.currentTimeMillis();
long slept = now - start;

if (slept >= durationInMillis) {
return SUCCESS;
}

condition.wait(durationInMillis - slept);
return SUCCESS;
}
});
}
} finally {
// Has to lock again *after* condition lock is released, otherwise it would be
// locked in reverse order condition > mutex opposed to normal locking order
// mutex > condition (as in signal, broadcast), which would lead to deadlock.
if (doLock) {
MutexOperations.lock(lock, thread, this);
}
}
Original file line number Diff line number Diff line change
@@ -804,7 +804,7 @@ public Object bitXOr(
Object a,
DynamicObject b,
@Cached("new()") SnippetNode snippetNode) {
return snippetNode.execute(frame, "a ^ Rubinius::Type.coerce_to_bitwise_operand(b)", "a", a, "b", b);
return snippetNode.execute(frame, "redo_coerced :^, b", "b", b);
}

}
Original file line number Diff line number Diff line change
@@ -31,6 +31,8 @@ DynamicObject createIO(DynamicObjectFactory factory,
int descriptor,
int mode);

boolean isIO(DynamicObject object);

DynamicObject getIBuffer(DynamicObject object);

int getLineNo(DynamicObject object);
Original file line number Diff line number Diff line change
@@ -12,10 +12,14 @@
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import org.jcodings.specific.ASCIIEncoding;
import org.jruby.RubyRandom;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.core.rope.CodeRange;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.util.ByteList;
import org.jruby.util.Random;

import java.math.BigInteger;
@@ -106,6 +110,33 @@ public DynamicObject randomizerGenSeed(DynamicObject randomizerClass) {
}
}

@Primitive(name = "randomizer_bytes", lowerFixnum = 1)
public static abstract class RandomizerBytesPrimitiveNode extends PrimitiveArrayArgumentsNode {

@TruffleBoundary
@Specialization
public DynamicObject genRandBytes(DynamicObject randomizer, int length) {
final Random random = Layouts.RANDOMIZER.getRandom(randomizer);
final byte[] bytes = new byte[length];
int idx = 0;
for (; length >= 4; length -= 4) {
int r = random.genrandInt32();
for (int i = 0; i < 4; ++i) {
bytes[idx++] = (byte) (r & 0xff);
r >>>= 8;
}
}
if (length > 0) {
int r = random.genrandInt32();
for (int i = 0; i < length; ++i) {
bytes[idx++] = (byte) (r & 0xff);
r >>>= 8;
}
}
return createString(RopeOperations.create(bytes, ASCIIEncoding.INSTANCE, CodeRange.CR_UNKNOWN));
}
}

@TruffleBoundary
private static int randomInt(Random random) {
return random.genrandInt32();
Original file line number Diff line number Diff line change
@@ -170,7 +170,7 @@ public AllocateNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, EMPTY_ASCII_8BIT_ROPE, null);
return allocateObjectNode.allocate(rubyClass, EMPTY_ASCII_8BIT_ROPE);
}

}
@@ -268,7 +268,7 @@ public DynamicObject multiply(DynamicObject string, int times,
@Cached("create()") MakeRepeatingNode makeRepeatingNode) {
final Rope repeated = makeRepeatingNode.executeMake(rope(string), times);

return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), repeated, null);
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), repeated);
}

@Specialization(guards = "isRubyBignum(times)")
@@ -528,7 +528,7 @@ private Object sliceRange(VirtualFrame frame, DynamicObject string, int begin, i
if (begin == stringLength) {
final ByteList byteList = new ByteList();
byteList.setEncoding(encoding(string));
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), RopeOperations.withEncodingVerySlow(RopeConstants.EMPTY_ASCII_8BIT_ROPE, encoding(string)), null);
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), RopeOperations.withEncodingVerySlow(RopeConstants.EMPTY_ASCII_8BIT_ROPE, encoding(string)));
}

end = StringOperations.normalizeIndex(stringLength, end);
@@ -1123,7 +1123,7 @@ private Object substr(Rope rope, DynamicObject string, int beg, int len) {
}

// TODO (nirvdrum 08-Jan-16) For CR_7BIT, we should always be able set to CR_7BIT. CR_VALID is trickier because any one character could be 7-bit.
final DynamicObject ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), substringRope, null);
final DynamicObject ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), substringRope);

return taintResultNode.maybeTaint(string, ret);
}
@@ -1275,7 +1275,7 @@ public DynamicObject initialize(DynamicObject self, NotProvided from) {
@Specialization
public DynamicObject initializeJavaString(DynamicObject self, String from) {
raiseIfFrozen(self);
StringOperations.setRope(self, StringOperations.createRope(from, UTF8Encoding.INSTANCE));
StringOperations.setRope(self, StringOperations.createRope(from, ASCIIEncoding.INSTANCE));
return self;
}

@@ -1710,7 +1710,7 @@ public DynamicObject dumpAsciiCompatible(DynamicObject string) {
ByteList outputBytes = dumpCommon(string);
outputBytes.setEncoding(encoding(string));

final DynamicObject result = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), StringOperations.ropeFromByteList(outputBytes, CodeRange.CR_7BIT), null);
final DynamicObject result = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), StringOperations.ropeFromByteList(outputBytes, CodeRange.CR_7BIT));

return result;
}
@@ -1734,7 +1734,7 @@ public DynamicObject dump(DynamicObject string) {

outputBytes.setEncoding(ASCIIEncoding.INSTANCE);

final DynamicObject result = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), StringOperations.ropeFromByteList(outputBytes, CodeRange.CR_7BIT), null);
final DynamicObject result = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), StringOperations.ropeFromByteList(outputBytes, CodeRange.CR_7BIT));

return result;
}
@@ -2343,28 +2343,6 @@ protected int getCacheLimit() {

}

@CoreMethod(names = "upcase", taintFrom = 0)
public abstract static class UpcaseNode extends CoreMethodArrayArgumentsNode {

@Child CallDispatchHeadNode dupNode;
@Child CallDispatchHeadNode upcaseBangNode;

public UpcaseNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
dupNode = DispatchHeadNodeFactory.createMethodCall(context);
upcaseBangNode = DispatchHeadNodeFactory.createMethodCall(context);
}

@Specialization
public Object upcase(VirtualFrame frame, DynamicObject string) {
final Object duped = dupNode.call(frame, string, "dup");
upcaseBangNode.call(frame, duped, "upcase!");

return duped;
}

}

@CoreMethod(names = "upcase!", raiseIfFrozenSelf = true)
@ImportStatic(StringGuards.class)
public abstract static class UpcaseBangNode extends CoreMethodArrayArgumentsNode {
@@ -2835,7 +2813,7 @@ public Object stringByteSubstring(DynamicObject string, int index, int length,
}

final Rope substringRope = makeSubstringNode.executeMake(rope, normalizedIndex, length);
final DynamicObject result = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), substringRope, null);
final DynamicObject result = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), substringRope);

return taintResultNode.maybeTaint(string, result);
}
@@ -3166,7 +3144,7 @@ public Object stringFindCharacterSingleByte(DynamicObject string, int offset) {

final Rope rope = rope(string);

final DynamicObject ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), makeSubstringNode.executeMake(rope, offset, 1), null);
final DynamicObject ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), makeSubstringNode.executeMake(rope, offset, 1));

return propagate(string, ret);
}
@@ -3183,10 +3161,10 @@ public Object stringFindCharacter(DynamicObject string, int offset) {

final DynamicObject ret;
if (StringSupport.MBCLEN_CHARFOUND_P(clen)) {
ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), makeSubstringNode.executeMake(rope, offset, clen), null);
ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), makeSubstringNode.executeMake(rope, offset, clen));
} else {
// TODO (nirvdrum 13-Jan-16) We know that the code range is CR_7BIT. Ensure we're not wasting time figuring that out again in the substring creation.
ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), makeSubstringNode.executeMake(rope, offset, 1), null);
ret = allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), makeSubstringNode.executeMake(rope, offset, 1));
}

return propagate(string, ret);
@@ -3889,15 +3867,15 @@ public StringPatternPrimitiveNode(RubyContext context, SourceSection sourceSecti
public DynamicObject stringPatternZero(DynamicObject stringClass, int size, int value) {
final Rope repeatingRope = makeRepeatingNode.executeMake(RopeConstants.ASCII_8BIT_SINGLE_BYTE_ROPES[value], size);

return allocateObjectNode.allocate(stringClass, repeatingRope, null);
return allocateObjectNode.allocate(stringClass, repeatingRope);
}

@Specialization(guards = { "isRubyString(string)", "patternFitsEvenly(string, size)" })
public DynamicObject stringPatternFitsEvenly(DynamicObject stringClass, int size, DynamicObject string) {
final Rope rope = rope(string);
final Rope repeatingRope = makeRepeatingNode.executeMake(rope, size / rope.byteLength());

return allocateObjectNode.allocate(stringClass, repeatingRope, null);
return allocateObjectNode.allocate(stringClass, repeatingRope);
}

@Specialization(guards = { "isRubyString(string)", "!patternFitsEvenly(string, size)" })
@@ -3919,7 +3897,7 @@ public DynamicObject stringPattern(DynamicObject stringClass, int size, DynamicO
final CodeRange codeRange = rope.getCodeRange() == CodeRange.CR_7BIT ? CodeRange.CR_7BIT : CodeRange.CR_UNKNOWN;
final Object characterLength = codeRange == CodeRange.CR_7BIT ? size : NotProvided.INSTANCE;

return allocateObjectNode.allocate(stringClass, makeLeafRopeNode.executeMake(bytes, encoding(string), codeRange, characterLength), null);
return allocateObjectNode.allocate(stringClass, makeLeafRopeNode.executeMake(bytes, encoding(string), codeRange, characterLength));
}

protected boolean patternFitsEvenly(DynamicObject string, int size) {
@@ -4327,8 +4305,7 @@ private DynamicObject makeRope(DynamicObject string, Rope rope, int beg, int len

final DynamicObject ret = allocateNode.allocate(
Layouts.BASIC_OBJECT.getLogicalClass(string),
makeSubstringNode.executeMake(rope, beg, len),
null);
makeSubstringNode.executeMake(rope, beg, len));

taintResultNode.maybeTaint(string, ret);

@@ -4352,8 +4329,7 @@ private DynamicObject makeBuffer(DynamicObject string, int beg, int len) {

final DynamicObject ret = allocateNode.allocate(
Layouts.BASIC_OBJECT.getLogicalClass(string),
new RopeBuffer(new ByteList(buffer.getByteList(), beg, len), buffer.getCodeRange(), buffer.isSingleByteOptimizable(), len),
null);
new RopeBuffer(new ByteList(buffer.getByteList(), beg, len), buffer.getCodeRange(), buffer.isSingleByteOptimizable(), len));

taintResultNode.maybeTaint(string, ret);

Original file line number Diff line number Diff line change
@@ -181,13 +181,15 @@ public Collection<DynamicObject> allSymbols() {
public static String checkInstanceVariableName(
RubyContext context,
String name,
Object receiver,
Node currentNode) {
// if (!IdUtil.isValidInstanceVariableName(name)) {

// check like Rubinius does for compatibility with their Struct Ruby implementation.
if (!(name.startsWith("@") && name.length() > 1 && IdUtil.isInitialCharacter(name.charAt(1)))) {
throw new RaiseException(context.getCoreExceptions().nameErrorInstanceNameNotAllowable(
name,
receiver,
currentNode));
}
return name;
@@ -197,10 +199,12 @@ public static String checkInstanceVariableName(
public static String checkClassVariableName(
RubyContext context,
String name,
Object receiver,
Node currentNode) {
if (!IdUtil.isValidClassVariableName(name)) {
throw new RaiseException(context.getCoreExceptions().nameErrorInstanceNameNotAllowable(
name,
receiver,
currentNode));
}
return name;
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
@@ -19,18 +20,24 @@
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.CoreMethodNode;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.cast.NameToJavaStringNodeGen;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyConstant;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.arguments.RubyArguments;
import org.jruby.truffle.language.constants.GetConstantNode;
import org.jruby.truffle.language.constants.LookupConstantNode;
import org.jruby.truffle.language.control.RaiseException;

@CoreClass("Truffle::CExt")
public class CExtNodes {
@@ -66,6 +73,27 @@ public long num2long(int num) {

}

@CoreMethod(names = "NUM2ULONG", isModuleFunction = true, required = 1)
public abstract static class NUM2ULONGNode extends CoreMethodArrayArgumentsNode {

@Specialization
public long num2ulong(int num) {
// TODO CS 2-May-16 what to do about the fact it's unsigned?
return num;
}

}

@CoreMethod(names = "NUM2DBL", isModuleFunction = true, required = 1)
public abstract static class NUM2DBLNode extends CoreMethodArrayArgumentsNode {

@Specialization
public double num2dbl(int num) {
return num;
}

}

@CoreMethod(names = "FIX2INT", isModuleFunction = true, required = 1)
public abstract static class FIX2INTNode extends CoreMethodArrayArgumentsNode {

@@ -154,6 +182,17 @@ public int long2num(int num) {

}

@CoreMethod(names = "ULONG2NUM", isModuleFunction = true, required = 1)
public abstract static class ULONG2NUMNode extends CoreMethodArrayArgumentsNode {

@Specialization
public int ulong2num(int num) {
// TODO CS 2-May-16 what to do about the fact it's unsigned?
return num;
}

}

@CoreMethod(names = "LONG2FIX", isModuleFunction = true, required = 1)
public abstract static class LONG2FIXNode extends CoreMethodArrayArgumentsNode {

@@ -164,6 +203,30 @@ public int long2fix(int num) {

}

@CoreMethod(names = "rb_long2int", isModuleFunction = true, required = 1)
public abstract static class Long2Int extends CoreMethodArrayArgumentsNode {

@Specialization
public int long2fix(int num) {
return num;
}

@Specialization(guards = "fitsIntoInteger(num)")
public int long2fixInRange(long num) {
return (int) num;
}

@Specialization(guards = "!fitsIntoInteger(num)")
public int long2fixOutOfRange(long num) {
throw new RaiseException(coreExceptions().rangeErrorConvertToInt(num, this));
}

protected boolean fitsIntoInteger(long num) {
return CoreLibrary.fitsIntoInteger(num);
}

}

@CoreMethod(names = "CExtString", isModuleFunction = true, required = 1)
public abstract static class CExtStringNode extends CoreMethodArrayArgumentsNode {

@@ -189,6 +252,23 @@ public DynamicObject toRubyString(DynamicObject string) {

}

@CoreMethod(names = "rb_block_given_p", isModuleFunction = true, needsCallerFrame = true)
public abstract static class BlockGivenNode extends CoreMethodArrayArgumentsNode {

@Specialization
public int blockGiven(MaterializedFrame callerFrame,
@Cached("createBinaryProfile()") ConditionProfile blockProfile) {
return blockProfile.profile(RubyArguments.getBlock(callerFrame) != null) ? 1 : 0;
}

@TruffleBoundary
@Specialization
public int blockGiven(NotProvided noCallerFrame) {
return RubyArguments.getBlock(Truffle.getRuntime().getCallerFrame().getFrame(FrameInstance.FrameAccess.READ_ONLY, false)) != null ? 1 : 0;
}

}

@CoreMethod(names = "get_block", isModuleFunction = true)
public abstract static class GetBlockNode extends CoreMethodArrayArgumentsNode {

@@ -229,4 +309,14 @@ public Object constGetFrom(VirtualFrame frame, DynamicObject module, String name

}

@CoreMethod(names = "rb_jt_io_handle", isModuleFunction = true)
public abstract static class IOHandleNode extends CoreMethodArrayArgumentsNode {

@Specialization(guards = "isRubyIO(io)")
public int ioHandle(DynamicObject io) {
return Layouts.IO.getDescriptor(io);
}

}

}
Original file line number Diff line number Diff line change
@@ -241,6 +241,10 @@ public static boolean isTracePoint(DynamicObject object) {
return Layouts.TRACE_POINT.isTracePoint(object);
}

public static boolean isRubyIO(DynamicObject object) {
return Layouts.IO.isIO(object);
}

public static boolean isNullPointer(DynamicObject pointer) {
return Layouts.POINTER.getPointer(pointer) == PointerPrimitiveNodes.NULL_POINTER;
}
Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ private Object doMissingConstant(
boolean isValidConstantName,
DynamicObject symbolName) {
if (!isValidConstantName) {
throw new RaiseException(coreExceptions().nameError(formatError(name), name, this));
throw new RaiseException(coreExceptions().nameError(formatError(name), module, name, this));
}

if (constMissingNode == null) {
Original file line number Diff line number Diff line change
@@ -21,27 +21,23 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;

public class StringLiteralNode extends RubyNode {

private final Rope rope;

@Child private AllocateObjectNode allocateObjectNode;

public StringLiteralNode(RubyContext context, SourceSection sourceSection, Rope rope) {
super(context, sourceSection);
this.rope = rope;
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, false, null, null);
}

@Override
public DynamicObject execute(VirtualFrame frame) {
return allocateObjectNode.allocate(coreLibrary().getStringClass(), rope, null);
return Layouts.STRING.createString(coreLibrary().getStringFactory(), rope);
}

}
Original file line number Diff line number Diff line change
@@ -32,18 +32,18 @@ public ObjectIVarGetNode(boolean checkName) {
@Specialization(guards = "name == cachedName", limit = "getCacheLimit()")
public Object ivarGetCached(DynamicObject object, String name,
@Cached("name") String cachedName,
@Cached("createReadFieldNode(checkName(cachedName))") ReadObjectFieldNode readObjectFieldNode) {
@Cached("createReadFieldNode(checkName(cachedName, object))") ReadObjectFieldNode readObjectFieldNode) {
return readObjectFieldNode.execute(object);
}

@TruffleBoundary
@Specialization(contains = "ivarGetCached")
public Object ivarGetUncached(DynamicObject object, String name) {
return object.get(checkName(name), nil());
return object.get(checkName(name, object), nil());
}

protected String checkName(String name) {
return checkName ? SymbolTable.checkInstanceVariableName(getContext(), name, this) : name;
protected String checkName(String name, DynamicObject object) {
return checkName ? SymbolTable.checkInstanceVariableName(getContext(), name, object, this) : name;
}

protected ReadObjectFieldNode createReadFieldNode(String name) {
Original file line number Diff line number Diff line change
@@ -32,20 +32,20 @@ public ObjectIVarSetNode(boolean checkName) {
@Specialization(guards = "name == cachedName", limit = "getCacheLimit()")
public Object ivarSetCached(DynamicObject object, String name, Object value,
@Cached("name") String cachedName,
@Cached("createWriteFieldNode(checkName(cachedName))") WriteObjectFieldNode writeObjectFieldNode) {
@Cached("createWriteFieldNode(checkName(cachedName, object))") WriteObjectFieldNode writeObjectFieldNode) {
writeObjectFieldNode.execute(object, value);
return value;
}

@TruffleBoundary
@Specialization(contains = "ivarSetCached")
public Object ivarSetUncached(DynamicObject object, String name, Object value) {
object.define(checkName(name), value, 0);
object.define(checkName(name, object), value, 0);
return value;
}

protected String checkName(String name) {
return checkName ? SymbolTable.checkInstanceVariableName(getContext(), name, this) : name;
protected String checkName(String name, DynamicObject object) {
return checkName ? SymbolTable.checkInstanceVariableName(getContext(), name, object, this) : name;
}

protected WriteObjectFieldNode createWriteFieldNode(String name) {
Original file line number Diff line number Diff line change
@@ -64,8 +64,6 @@
import org.jruby.truffle.language.SnippetNode;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DoesRespondDispatchHeadNode;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;
import org.jruby.truffle.language.objects.ReadObjectFieldNode;
import org.jruby.truffle.language.objects.ReadObjectFieldNodeGen;
import org.jruby.truffle.language.objects.TaintNode;
@@ -97,23 +95,6 @@
@CoreClass("Psych::Parser")
public abstract class PsychParserNodes {

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
return allocateNode.allocate(rubyClass, null, null);
}

}

@CoreMethod(names = "parse", required = 1, optional = 1)
public abstract static class ParseNode extends CoreMethodArrayArgumentsNode {

Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ public class SimpleShell {
public SimpleShell(RubyContext context) {
this.context = context;

if (!TruffleOptions.AOT && System.console() == null) {
if (TruffleOptions.AOT || System.console() == null) {
shellInterface = new StandardShellInterface();
} else {
shellInterface = new ConsoleShellInterface();
4 changes: 0 additions & 4 deletions truffle/src/main/ruby/core/comparable.rb
Original file line number Diff line number Diff line change
@@ -29,15 +29,11 @@ def ==(other)
return true if equal?(other)

return false if Thread.detect_recursion(self, other) do
begin
unless comp = (self <=> other)
return false
end

return Comparable.compare_int(comp) == 0
rescue StandardError
return false
end
end
end

14 changes: 6 additions & 8 deletions truffle/src/main/ruby/core/exception.rb
Original file line number Diff line number Diff line change
@@ -181,22 +181,20 @@ class LocalJumpError < StandardError
end

class NameError < StandardError
attr_reader :name

def initialize(*args)
super(args.shift)
@name = args.shift
name = args.size > 1 ? args.pop : nil
super(*args)
Truffle.invoke_primitive :name_error_set_name, self, name
end
end

class NoMethodError < NameError
attr_reader :name
attr_reader :args

def initialize(*arguments)
super(arguments.shift)
@name = arguments.shift
@args = arguments.shift
args = arguments.size > 2 ? arguments.pop : nil
super(*arguments) # TODO BJF Jul 24, 2016 Need to handle NoMethodError.new(1,2,3,4)
Truffle.invoke_primitive :no_method_error_set_args, self, args
end
end

10 changes: 1 addition & 9 deletions truffle/src/main/ruby/core/random.rb
Original file line number Diff line number Diff line change
@@ -191,14 +191,6 @@ def ==(other)
# Returns a random binary string.
# The argument size specified the length of the result string.
def bytes(length)
length = Rubinius::Type.coerce_to length, Integer, :to_int
s = ''
i = 0
while i < length
s << @randomizer.random_integer(255).chr
i += 1
end

s
Truffle.invoke_primitive :randomizer_bytes, @randomizer, length
end
end
6 changes: 6 additions & 0 deletions truffle/src/main/ruby/core/string.rb
Original file line number Diff line number Diff line change
@@ -1662,6 +1662,12 @@ def downcase
s
end

def upcase
s = dup
s.upcase!
s
end

def +@
frozen? ? dup : self
end
Loading

0 comments on commit fb31d66

Please sign in to comment.