Skip to content

Commit bd817cd

Browse files
committed
[GR-20709] [GR-20837] [GR-19473] [GR-20976] Bug fixes for 20.0.
PullRequest: truffleruby/1334
2 parents c4ee0e2 + 19bbce1 commit bd817cd

File tree

22 files changed

+208
-65
lines changed

22 files changed

+208
-65
lines changed

.gitattributes

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Merge options
22

3-
/CHANGELOG.md merge=union
43

54
# Rules for GitHub's Linguist language-classification system. We're abusing the
65
# 'vendored' attribute to exclude files as a lot of this isn't really vendored,

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ New features:
55
* Enable and document `--coverage` option (#1840, @chrisseaton).
66
* Update the internal LLVM toolchain to LLVM 9 and reduce its download size.
77
* Updated to Ruby 2.6.5 (#1749).
8+
* Automatically set `PKG_CONFIG_PATH` as needed for compiling OpenSSL on macOS (#1830).
89

910
Bug fixes:
1011

@@ -76,6 +77,8 @@ Bug fixes:
7677
* Fixed `IO.try_convert` parameter conversion.
7778
* Fixed linking of always-inline C API functions with `-std=gnu90` (#1837, #1879).
7879
* Avoid race conditions during `gem install` by using a single download thread.
80+
* `RSTRING_PTR()` now always returns a native pointer, resolving two bugs `memcpy`ing to (#1822) and from (#1772) Ruby Strings.
81+
* Do not use gems precompiled for MRI on TruffleRuby (#1837).
7982

8083
Compatibility:
8184

ci.jsonnet

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ local part_definitions = {
7676
environment+: { path+:: ["$MAVEN_HOME/bin"] },
7777
},
7878

79-
build: {
79+
build_no_clean: {
8080
setup+: [["mx", "sversions"]] +
8181
# aot-build.log is used for the build-stats metrics, in other cases it does no harm
8282
jt(["build", "--env", self.mx_env] + self.jt_build_options + ["--"] + self.mx_build_options + ["|", "tee", "aot-build.log"]) +
@@ -86,6 +86,11 @@ local part_definitions = {
8686
],
8787
},
8888

89+
build: $.use.build_no_clean + {
90+
# Clean build results to make sure nothing refers to them while testing
91+
setup+: jt(["mx", "--env", self.mx_env, "clean"]),
92+
},
93+
8994
clone_enterprise: {
9095
setup+: [["mx", "sversions"]] + jt(["checkout_enterprise_revision"]),
9196
},
@@ -273,18 +278,19 @@ local part_definitions = {
273278

274279
run: {
275280
test_unit_tck_specs: {
276-
run+: jt(["test", "unit"]) +
277-
jt(["test", "tck"]) +
278-
jt(["test", "specs"]) +
279-
jt(["test", "specs", ":next"]),
281+
run+: jt(["test", "specs"]) +
282+
jt(["test", "specs", ":next"]) +
283+
jt(["build"]) + # We need mx distributions to run unit tests
284+
jt(["test", "unit"]) +
285+
jt(["test", "tck"]),
280286
},
281287

282288
test_fast: {
283289
run+: jt(["test", "fast"]),
284290
},
285291

286292
lint: {
287-
is_after:: ["$.use.build"],
293+
is_after:: ["$.use.build_no_clean"],
288294
downloads+: {
289295
JDT: { name: "ecj", version: "4.5.1", platformspecific: false },
290296
ECLIPSE: { version: "4.5.2", name: "eclipse", platformspecific: true },
@@ -427,7 +433,7 @@ local composition_environment = utils.add_inclusion_tracking(part_definitions, "
427433

428434
test_builds:
429435
{
430-
"ruby-lint": $.platform.linux + $.cap.gate + $.jdk.v8 + $.use.common + $.env.jvm + $.use.build + $.run.lint + { timelimit: "30:00" },
436+
"ruby-lint": $.platform.linux + $.cap.gate + $.jdk.v8 + $.use.common + $.env.jvm + $.use.build_no_clean + $.run.lint + { timelimit: "30:00" },
431437
} +
432438

433439
{

lib/cext/include/truffleruby/truffleruby.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ int rb_encdb_alias(const char *alias, const char *orig);
158158
VALUE rb_ivar_lookup(VALUE object, const char *name, VALUE default_value);
159159

160160
// Additional macro to make sure the RSTRING_PTR and the bytes are in native memory, for testing.
161-
#define NATIVE_RSTRING_PTR(str) ((char*) polyglot_as_i64(polyglot_invoke(RSTRING_PTR(str), "polyglot_address")))
161+
#define NATIVE_RSTRING_PTR(str) ((char*) polyglot_as_i64(RUBY_CEXT_INVOKE_NO_WRAP("NATIVE_RSTRING_PTR", str)))
162162

163163
// Inline implementations
164164

lib/truffle/rubygems/defaults/truffleruby.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ module Gem
1616
def self.default_dir
1717
@default_dir ||= "#{Truffle::Boot.ruby_home or raise 'TruffleRuby home not found'}/lib/gems"
1818
end
19+
20+
# Only report the RUBY platform as supported to make sure gems precompiled for MRI are not used.
21+
# TruffleRuby has a different ABI and cannot reuse gems precompiled for MRI.
22+
# See https://github.com/rubygems/rubygems/issues/2945
23+
Gem.platforms = [Gem::Platform::RUBY]
1924
end

lib/truffle/truffle/cext.rb

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,31 +149,31 @@ def initialize(string)
149149
end
150150

151151
def size
152-
Truffle::CExt.string_pointer_size(@string)
152+
TrufflePrimitive.string_pointer_size(@string)
153153
end
154154

155155
def polyglot_pointer?
156156
true
157157
end
158158

159159
def polyglot_address
160-
@address ||= Truffle::CExt.string_pointer_to_native(@string)
160+
@address ||= TrufflePrimitive.string_pointer_to_native(@string)
161161
end
162162

163163
# Every IS_POINTER object should also have TO_NATIVE
164164
def polyglot_to_native
165165
end
166166

167167
def [](index)
168-
Truffle::CExt.string_pointer_read(@string, index)
168+
TrufflePrimitive.string_pointer_read(@string, index)
169169
end
170170

171171
def []=(index, value)
172-
Truffle::CExt.string_pointer_write(@string, index, value)
172+
TrufflePrimitive.string_pointer_write(@string, index, value)
173173
end
174174

175175
def native?
176-
Truffle::CExt.string_pointer_is_native?(@string)
176+
TrufflePrimitive.string_pointer_is_native?(@string)
177177
end
178178

179179
alias_method :to_str, :string
@@ -231,7 +231,7 @@ def polyglot_pointer?
231231
end
232232

233233
def polyglot_address
234-
@address ||= Truffle::CExt.string_pointer_to_native(@string) + @string.bytesize
234+
@address ||= TrufflePrimitive.string_pointer_to_native(@string) + @string.bytesize
235235
end
236236

237237
# Every IS_POINTER object should also have TO_NATIVE
@@ -1846,10 +1846,18 @@ def rb_enc_from_native_encoding(rb_encoding)
18461846
RbEncoding.get_encoding_from_native(rb_encoding)
18471847
end
18481848

1849+
def native_string?(string)
1850+
TrufflePrimitive.string_pointer_is_native?(string)
1851+
end
1852+
18491853
def RSTRING_PTR(string)
18501854
RStringPtr.new(string)
18511855
end
18521856

1857+
def NATIVE_RSTRING_PTR(string)
1858+
TrufflePrimitive.string_pointer_to_native(string)
1859+
end
1860+
18531861
def RSTRING_END(string)
18541862
RStringEndPtr.new(string)
18551863
end

lib/truffle/truffle/lazy-rubygems.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# Otherwise, --disable-gems would degrade startup which is counter-intuitive.
1111
Truffle::Boot.delay do
1212
if Truffle::Boot.get_option 'rubygems'
13+
module Truffle::LazyRubyGems
14+
end
15+
1316
module Kernel
1417
# Take this alias name so RubyGems will reuse this copy
1518
# and skip the method below once RubyGems is loaded.
@@ -19,11 +22,19 @@ module Kernel
1922
begin
2023
gem_original_require(path)
2124
rescue LoadError
22-
require 'rubygems'
23-
require path
25+
gem_original_require 'rubygems'
26+
27+
# Check that #require was redefined by RubyGems, otherwise we would end up in infinite recursion
28+
new_require = ::Kernel.instance_method(:require)
29+
if new_require == Truffle::LazyRubyGems::LAZY_REQUIRE
30+
raise 'RubyGems did not redefine #require as expected, make sure $LOAD_PATH and home are set correctly'
31+
end
32+
new_require.bind(self).call(path)
2433
end
2534
end
2635

36+
Truffle::LazyRubyGems::LAZY_REQUIRE = instance_method(:require)
37+
2738
private def gem(*args)
2839
require 'rubygems'
2940
gem(*args)

lib/truffle/truffle/openssl-prefix.rb

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,26 @@
1313
macOS = RbConfig::CONFIG['host_os'].include?('darwin')
1414

1515
if macOS && !ENV['OPENSSL_PREFIX']
16-
homebrew_prefix = `brew --prefix openssl 2>/dev/null`.chomp
17-
if $?.success? and Dir.exist?(homebrew_prefix) # Homebrew
18-
ENV['OPENSSL_PREFIX'] = homebrew_prefix
16+
homebrew = `brew --prefix 2>/dev/null`.strip
17+
unless $?.success? and !homebrew.empty? and Dir.exist?(homebrew)
18+
homebrew = nil
19+
end
20+
21+
if homebrew and prefix = "#{homebrew}/opt/openssl@1.1" and Dir.exist?(prefix)
22+
ENV['OPENSSL_PREFIX'] = prefix
23+
elsif homebrew and prefix = "#{homebrew}/opt/openssl" and Dir.exist?(prefix)
24+
ENV['OPENSSL_PREFIX'] = prefix
1925
elsif Dir.exist?('/opt/local/include/openssl') # MacPorts
2026
ENV['OPENSSL_PREFIX'] = '/opt/local'
2127
else
2228
abort 'Could not find OpenSSL headers, install via Homebrew or MacPorts or set OPENSSL_PREFIX'
2329
end
2430
end
31+
32+
if openssl_prefix = ENV['OPENSSL_PREFIX']
33+
Truffle::Debug.log_config("Found OpenSSL in #{openssl_prefix}")
34+
35+
# We need to set PKG_CONFIG_PATH too, see https://github.com/oracle/truffleruby/issues/1830
36+
# OpenSSL's extconf.rb calls the pkg_config() helper.
37+
ENV['PKG_CONFIG_PATH'] = ["#{openssl_prefix}/lib/pkgconfig", *ENV['PKG_CONFIG_PATH']].join(':')
38+
end

spec/ruby/optional/capi/ext/string_spec.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,26 @@ VALUE string_spec_RSTRING_PTR_iterate(VALUE self, VALUE str) {
284284
return Qnil;
285285
}
286286

287+
VALUE string_spec_RSTRING_PTR_iterate_uint32(VALUE self, VALUE str) {
288+
int i;
289+
uint32_t* ptr;
290+
int l = RSTRING_LEN(str) / sizeof(uint32_t);
291+
292+
ptr = (uint32_t *)RSTRING_PTR(str);
293+
for(i = 0; i < l; i++) {
294+
rb_yield(UINT2NUM(ptr[i]));
295+
}
296+
return Qnil;
297+
}
298+
299+
VALUE string_spec_RSTRING_PTR_short_memcpy(VALUE self, VALUE str) {
300+
// Short memcpy operations may be optimised by the compiler to a single write.
301+
if (RSTRING_LEN(str) >= 8) {
302+
memcpy(RSTRING_PTR(str), "Infinity", 8);
303+
}
304+
return str;
305+
}
306+
287307
VALUE string_spec_RSTRING_PTR_assign(VALUE self, VALUE str, VALUE chr) {
288308
int i;
289309
char c;
@@ -477,6 +497,8 @@ void Init_string_spec(void) {
477497
rb_define_method(cls, "RSTRING_LEN", string_spec_RSTRING_LEN, 1);
478498
rb_define_method(cls, "RSTRING_LENINT", string_spec_RSTRING_LENINT, 1);
479499
rb_define_method(cls, "RSTRING_PTR_iterate", string_spec_RSTRING_PTR_iterate, 1);
500+
rb_define_method(cls, "RSTRING_PTR_iterate_uint32", string_spec_RSTRING_PTR_iterate_uint32, 1);
501+
rb_define_method(cls, "RSTRING_PTR_short_memcpy", string_spec_RSTRING_PTR_short_memcpy, 1);
480502
rb_define_method(cls, "RSTRING_PTR_assign", string_spec_RSTRING_PTR_assign, 2);
481503
rb_define_method(cls, "RSTRING_PTR_set", string_spec_RSTRING_PTR_set, 3);
482504
rb_define_method(cls, "RSTRING_PTR_after_funcall", string_spec_RSTRING_PTR_after_funcall, 2);

spec/ruby/optional/capi/string_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,24 @@ def inspect
513513
end
514514
chars.should == [55, 48, 227, 131, 145, 227, 130, 175]
515515
end
516+
517+
it "returns a pointer which can be cast and used as another type" do
518+
s = "70パク".
519+
encode(Encoding::UTF_16LE).
520+
force_encoding(Encoding::UTF_16LE).
521+
encode(Encoding::UTF_8)
522+
523+
ints = []
524+
@s.RSTRING_PTR_iterate_uint32(s) do |i|
525+
ints << i
526+
end
527+
ints.should == s.unpack('LL')
528+
end
529+
530+
it "allows a short memcpy to the string which may be converted to a single write operation by the compiler" do
531+
str = " "
532+
@s.RSTRING_PTR_short_memcpy(str).should == "Infinity"
533+
end
516534
end
517535

518536
describe "RSTRING_LEN" do

spec/truffle/capi/string_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@
1515
@s = CApiTruffleStringSpecs.new
1616
end
1717

18-
it "does not store the String to native memory if not needed" do
18+
it "stores the String to native memory even if not needed for efficiency" do
1919
str = "foobar"
2020
@s.string_ptr(str).should == "f"
21-
Truffle::CExt.string_pointer_is_native?(str).should == false
21+
Truffle::CExt.native_string?(str).should == true
2222
end
2323

2424
it "stores the String to native memory if the address is returned" do
2525
str = "foobar"
2626
@s.string_ptr_return_address(str).should be_kind_of(Integer)
27-
Truffle::CExt.string_pointer_is_native?(str).should == true
27+
Truffle::CExt.native_string?(str).should == true
2828
end
2929
end
3030

@@ -35,8 +35,8 @@
3535

3636
it "ensures the String is stored in native memory" do
3737
str = "foobar"
38-
Truffle::CExt.string_pointer_is_native?(str).should == false
38+
Truffle::CExt.native_string?(str).should == false
3939
@s.NATIVE_RSTRING_PTR(str)
40-
Truffle::CExt.string_pointer_is_native?(str).should == true
40+
Truffle::CExt.native_string?(str).should == true
4141
end
4242
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. This
2+
# code is released under a tri EPL/GPL/LGPL license. You can use it,
3+
# redistribute it and/or modify it under the terms of the:
4+
#
5+
# Eclipse Public License version 2.0, or
6+
# GNU General Public License version 2, or
7+
# GNU Lesser General Public License version 2.1.
8+
# OTHER DEALINGS IN THE SOFTWARE.
9+
10+
require_relative '../../ruby/spec_helper'
11+
require 'rubygems'
12+
13+
describe "Gem.platforms" do
14+
it "returns only [RUBY] on TruffleRuby to not use gems precompiled for MRI" do
15+
Gem.platforms.should == [Gem::Platform::RUBY]
16+
end
17+
end

src/main/c/cext/ruby.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ char *rb_string_value_cstr(VALUE *value_pointer) {
812812
}
813813

814814
char *RSTRING_PTR_IMPL(VALUE string) {
815-
return (char *)polyglot_as_i8_array(RUBY_CEXT_INVOKE_NO_WRAP("RSTRING_PTR", string));
815+
return NATIVE_RSTRING_PTR(string);
816816
}
817817

818818
char *RSTRING_END(VALUE string) {

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -957,8 +957,8 @@ protected Object rbHash(Object object) {
957957
}
958958
}
959959

960-
@CoreMethod(names = "string_pointer_size", onSingleton = true, required = 1)
961-
public abstract static class StringPointerSizeNode extends CoreMethodArrayArgumentsNode {
960+
@Primitive(name = "string_pointer_size")
961+
public abstract static class StringPointerSizeNode extends PrimitiveArrayArgumentsNode {
962962

963963
@Specialization(guards = "isRubyString(string)")
964964
protected int size(DynamicObject string) {
@@ -1010,8 +1010,8 @@ protected NativeRope toNative(DynamicObject string,
10101010

10111011
}
10121012

1013-
@CoreMethod(names = "string_pointer_to_native", onSingleton = true, required = 1)
1014-
public abstract static class StringPointerToNativeNode extends CoreMethodArrayArgumentsNode {
1013+
@Primitive(name = "string_pointer_to_native")
1014+
public abstract static class StringPointerToNativeNode extends PrimitiveArrayArgumentsNode {
10151015

10161016
@Specialization(guards = "isRubyString(string)")
10171017
protected long toNative(DynamicObject string,
@@ -1038,8 +1038,8 @@ protected DynamicObject toNative(DynamicObject string,
10381038

10391039
}
10401040

1041-
@CoreMethod(names = "string_pointer_is_native?", onSingleton = true, required = 1)
1042-
public abstract static class StringPointerIsNativeNode extends CoreMethodArrayArgumentsNode {
1041+
@Primitive(name = "string_pointer_is_native?")
1042+
public abstract static class StringPointerIsNativeNode extends PrimitiveArrayArgumentsNode {
10431043

10441044
@Specialization(guards = "isRubyString(string)")
10451045
protected boolean isNative(DynamicObject string) {
@@ -1048,8 +1048,8 @@ protected boolean isNative(DynamicObject string) {
10481048

10491049
}
10501050

1051-
@CoreMethod(names = "string_pointer_read", onSingleton = true, required = 2, lowerFixnum = 2)
1052-
public abstract static class StringPointerReadNode extends CoreMethodArrayArgumentsNode {
1051+
@Primitive(name = "string_pointer_read", lowerFixnum = 1)
1052+
public abstract static class StringPointerReadNode extends PrimitiveArrayArgumentsNode {
10531053

10541054
@Specialization(guards = "isRubyString(string)")
10551055
protected Object read(DynamicObject string, int index,
@@ -1068,8 +1068,8 @@ protected Object read(DynamicObject string, int index,
10681068

10691069
}
10701070

1071-
@CoreMethod(names = "string_pointer_write", onSingleton = true, required = 3, lowerFixnum = { 2, 3 })
1072-
public abstract static class StringPointerWriteNode extends CoreMethodArrayArgumentsNode {
1071+
@Primitive(name = "string_pointer_write", lowerFixnum = { 1, 2 })
1072+
public abstract static class StringPointerWriteNode extends PrimitiveArrayArgumentsNode {
10731073

10741074
@Specialization(guards = "isRubyString(string)")
10751075
protected int write(DynamicObject string, int index, int value,

0 commit comments

Comments
 (0)