Skip to content

Commit

Permalink
Showing 26 changed files with 404 additions and 308 deletions.
2 changes: 2 additions & 0 deletions core/pom.rb
Original file line number Diff line number Diff line change
@@ -73,6 +73,8 @@
jar 'org.jruby:joda-timezones:${tzdata.version}', :scope => '${tzdata.scope}'
jar 'joda-time:joda-time:${joda.time.version}'

jar 'com.boundary:high-scale-lib:1.0.6'

plugin_management do
plugin( 'org.eclipse.m2e:lifecycle-mapping:1.0.0',
'lifecycleMappingMetadata' => {
5 changes: 5 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -263,6 +263,11 @@ DO NOT MODIFIY - GENERATED CODE
<artifactId>joda-time</artifactId>
<version>${joda.time.version}</version>
</dependency>
<dependency>
<groupId>com.boundary</groupId>
<artifactId>high-scale-lib</artifactId>
<version>1.0.6</version>
</dependency>
</dependencies>
<build>
<defaultGoal>package</defaultGoal>
1 change: 0 additions & 1 deletion core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -1613,7 +1613,6 @@ public RubyModule defineModuleUnder(String name) {
}

private void addAccessor(ThreadContext context, RubySymbol identifier, Visibility visibility, boolean readable, boolean writeable) {
ByteList idBytes = identifier.getBytes();
String internedIdentifier = identifier.toString();

final Ruby runtime = context.runtime;
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/RubyString.java
Original file line number Diff line number Diff line change
@@ -5251,6 +5251,7 @@ public IRubyObject force_encoding(ThreadContext context, IRubyObject enc) {
}

private IRubyObject force_encoding(Encoding encoding) {
modifyCheck();
modify19();
associateEncoding(encoding);
clearCodeRange();
22 changes: 8 additions & 14 deletions core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
import java.lang.reflect.Modifier;
import java.util.ArrayList;

import org.cliffc.high_scale_lib.NonBlockingHashMapLong;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.exceptions.RaiseException;
@@ -27,16 +28,15 @@

public abstract class RubyToJavaInvoker<T extends JavaCallable> extends JavaMethod {

static final IntHashMap NULL_CACHE = IntHashMap.nullMap();
static final NonBlockingHashMapLong NULL_CACHE = new NonBlockingHashMapLong();

protected final T javaCallable; /* null if multiple callable members */
protected final T[][] javaCallables; /* != null if javaCallable == null */
protected final T[] javaVarargsCallables; /* != null if any var args callables */

// in case multiple callables (overloaded Java method - same name different args)
// for the invoker exists CallableSelector caches resolution based on args here
final IntHashMap<T> writeCache;
volatile IntHashMap<T> readCache;
final NonBlockingHashMapLong<T> cache;

private final Ruby runtime;

@@ -55,8 +55,7 @@ public abstract class RubyToJavaInvoker<T extends JavaCallable> extends JavaMeth
minVarArgsArity = getMemberArity(member) - 1;
}

writeCache = NULL_CACHE; // if there's a single callable - matching (and thus the cache) won't be used
readCache = writeCache;
cache = NULL_CACHE; // if there's a single callable - matching (and thus the cache) won't be used

this.javaCallable = callable;
this.javaCallables = null;
@@ -86,8 +85,7 @@ public abstract class RubyToJavaInvoker<T extends JavaCallable> extends JavaMeth
}
callables = null;

writeCache = NULL_CACHE; // if there's a single callable - matching (and thus the cache) won't be used
readCache = writeCache;
cache = NULL_CACHE; // if there's a single callable - matching (and thus the cache) won't be used
}
else {
callable = null; maxArity = -1; minArity = Integer.MAX_VALUE;
@@ -142,8 +140,7 @@ public abstract class RubyToJavaInvoker<T extends JavaCallable> extends JavaMeth
varargsCallables = varArgs.toArray( createCallableArray(varArgs.size()) );
}

writeCache = newCallableCache();
readCache = (IntHashMap<T>)writeCache.clone();
cache = new NonBlockingHashMapLong<>(8);
}

this.javaCallable = callable;
@@ -196,14 +193,11 @@ private boolean setNativeCallIfPublic(final Method method) {
}

public T getSignature(int signatureCode) {
return readCache.get(signatureCode);
return cache.get(signatureCode);
}

public void putSignature(int signatureCode, T callable) {
synchronized (writeCache) {
writeCache.put(signatureCode, callable);
readCache = (IntHashMap<T>)writeCache.clone();
}
cache.put(signatureCode, callable);
}

protected abstract T createCallable(Ruby runtime, Member member);
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/util/cli/Options.java
Original file line number Diff line number Diff line change
@@ -240,6 +240,7 @@ public class Options {
public static final Option<Integer> TRUFFLE_ALLOCATE_CLASS_CACHE = integer(TRUFFLE, "truffle.allocate_class.cache", TRUFFLE_DEFAULT_CACHE.load(), "Allocation size class cache size");
public static final Option<Integer> TRUFFLE_PACK_CACHE = integer(TRUFFLE, "truffle.pack.cache", TRUFFLE_DEFAULT_CACHE.load(), "Array#pack cache size");
public static final Option<Integer> TRUFFLE_EVAL_CACHE = integer(TRUFFLE, "truffle.eval.cache", TRUFFLE_DEFAULT_CACHE.load(), "eval lookup cache size");
public static final Option<Integer> ENCODING_COMPATIBILE_QUERY_CACHE = integer(TRUFFLE, "truffle.encoding_comptabile_query.cache", TRUFFLE_DEFAULT_CACHE.load(), "Encoding.compatible? cache size");

public static final Option<Boolean> TRUFFLE_CORE_ALWAYS_CLONE = bool(TRUFFLE, "truffle.core.always_clone", true, "Always clone built-in core methods.");
public static final Option<Boolean> TRUFFLE_YIELD_ALWAYS_CLONE = bool(TRUFFLE, "truffle.yield.always_clone", true, "Always clone yields.");
5 changes: 5 additions & 0 deletions spec/ruby/core/string/force_encoding_spec.rb
Original file line number Diff line number Diff line change
@@ -44,5 +44,10 @@
str = "\u{8612}"
str.dup.force_encoding('utf-16le').should_not == str.encode('utf-16le')
end

it "raises a RuntimeError if self is frozen" do
str = "abcd".freeze
lambda { str.force_encoding(str.encoding) }.should raise_error(RuntimeError)
end
end
end
4 changes: 4 additions & 0 deletions tool/truffle-findbugs-exclude.xml
Original file line number Diff line number Diff line change
@@ -82,6 +82,10 @@
<Class name="org.jruby.truffle.nodes.constants.LookupConstantNode" />
<Bug pattern="ES_COMPARING_PARAMETER_STRING_WITH_EQ" />
</Match>
<Match>
<Class name="org.jruby.truffle.nodes.constants.GetConstantNode" />
<Bug pattern="ES_COMPARING_PARAMETER_STRING_WITH_EQ" />
</Match>

<!-- Stuff where we're genuinely doing something complicated and we do know what we're doing -->

23 changes: 12 additions & 11 deletions tool/truffle/jruby_truffle_runner/lib/jruby+truffle_runner.rb
Original file line number Diff line number Diff line change
@@ -25,6 +25,13 @@ class JRubyTruffleRunner
assign_new_value = -> (new, old) { new }
add_to_array = -> (new, old) { old << new }
merge_hash = -> ((k, v), old) { old.merge k => v }
apply_pattern = -> (pattern, old) do
Dir.glob(pattern) do |file|
next if @options[:run][:exclude_pattern].any? { |p| /#{p}/ =~ file }
@options[:run][:require] << File.expand_path(file)
end
old
end

# Format:
# subcommand_name: {
@@ -60,8 +67,8 @@ class JRubyTruffleRunner
rebuild: ['--rebuild', 'Run `jt rebuild` in JRuby', assign_new_value, false],
debug: ['-d', '--debug', 'JVM remote debugging', assign_new_value, false],
require: ['-r', '--require FILE', 'Files to require, same as Ruby\'s -r', add_to_array, []],
require_pattern: ['--require-pattern DIR_GLOB_PATTERN', 'Files matching the pattern will be required', add_to_array, []],
exclude_pattern: ['--exclude-pattern REGEXP', 'Files matching the regexp will not be required by --require-pattern', add_to_array, []],
require_pattern: ['--require-pattern DIR_GLOB_PATTERN', 'Files matching the pattern will be required', apply_pattern, nil],
exclude_pattern: ['--exclude-pattern REGEXP', 'Files matching the regexp will not be required by --require-pattern (applies to subsequent --require-pattern options)', add_to_array, []],
load_path: ['-I', '--load-path LOAD_PATH', 'Paths to add to load path, same as Ruby\'s -I', add_to_array, []],
executable: ['-S', '--executable NAME', 'finds and runs an executable of a gem', assign_new_value, nil],
jexception: ['--jexception', 'print Java exceptions', assign_new_value, false]
@@ -129,7 +136,7 @@ def initialize(argv = ARGV)
build_option_parsers

vm_options, argv_after_vm_options = collect_vm_options argv
subcommand, *argv_after_global = @option_parsers[:global].order argv_after_vm_options
subcommand, *argv_after_global = @option_parsers[:global].order argv_after_vm_options

if subcommand.nil?
print_options
@@ -169,7 +176,7 @@ def build_option_parsers

option_parser.on(*args, description + " (default: #{default.inspect})") do |new_value|
old_value = @options[group][option]
@options[group][option] = block.call new_value, old_value
@options[group][option] = instance_exec new_value, old_value, &block
end
end
end
@@ -179,7 +186,7 @@ def build_option_parsers
end

def collect_vm_options(argv)
vm_options = []
vm_options = []
other_options = argv.reject do |arg|
vm = arg.start_with? '-J'
vm_options.push arg if vm
@@ -315,12 +322,6 @@ def subcommand_run(vm_options, rest)
end

core_load_path = "#{jruby_path}/truffle/src/main/ruby"
@options[:run][:require_pattern].each do |pattern|
Dir.glob(pattern) do |file|
next if @options[:run][:exclude_pattern].any? { |p| /#{p}/ =~ file }
@options[:run][:require] << File.expand_path(file)
end
end

cmd_options = [
*(['-X+T', *vm_options, "-Xtruffle.core.load_path=#{core_load_path}"] unless @options[:run][:test]),
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.KernelNodes.RequireNode;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
@@ -32,6 +33,7 @@
public abstract class GetConstantNode extends RubyNode {

private final RestartableReadConstantNode readConstantNode;
private @Child CallDispatchHeadNode constMissingNode;

public GetConstantNode(RubyContext context, SourceSection sourceSection, RestartableReadConstantNode readConstantNode) {
super(context, sourceSection);
@@ -47,8 +49,8 @@ protected Object getConstant(DynamicObject module, String name, RubyConstant con

@Specialization(guards = { "constant != null", "constant.isAutoload()" })
protected Object autoloadConstant(VirtualFrame frame, DynamicObject module, String name, RubyConstant constant,
@Cached("createRequireNode()") RequireNode requireNode,
@Cached("deepCopyReadConstantNode()") RestartableReadConstantNode readConstantNode) {
@Cached("createRequireNode()") RequireNode requireNode,
@Cached("deepCopyReadConstantNode()") RestartableReadConstantNode readConstantNode) {

final DynamicObject path = (DynamicObject) constant.getValue();

@@ -64,15 +66,35 @@ protected Object autoloadConstant(VirtualFrame frame, DynamicObject module, Stri
}
}

@Specialization(guards = "constant == null")
protected Object missingConstant(VirtualFrame frame, DynamicObject module, String name, Object constant,
@Specialization(guards = {
"constant == null",
"guardName(name, cachedName, sameNameProfile)"
}, limit = "getCacheLimit()")
protected Object missingConstantCached(VirtualFrame frame, DynamicObject module, String name, Object constant,
@Cached("name") String cachedName,
@Cached("isValidConstantName(name)") boolean isValidConstantName,
@Cached("createConstMissingNode()") CallDispatchHeadNode constMissingNode,
@Cached("getSymbol(name)") DynamicObject symbolName) {
@Cached("getSymbol(name)") DynamicObject symbolName,
@Cached("createBinaryProfile()") ConditionProfile sameNameProfile) {
return doMissingConstant(frame, module, name, isValidConstantName, symbolName);
}

@Specialization(guards = "constant == null")
protected Object missingConstantUncached(VirtualFrame frame, DynamicObject module, String name, Object constant) {
final boolean isValidConstantName = isValidConstantName(name);
return doMissingConstant(frame, module, name, isValidConstantName, getSymbol(name));
}

private Object doMissingConstant(VirtualFrame frame, DynamicObject module, String name, boolean isValidConstantName, DynamicObject symbolName) {
if (!isValidConstantName) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameError(String.format("wrong constant name %s", name), name, this));
}

if (constMissingNode == null) {
CompilerDirectives.transferToInterpreter();
constMissingNode = insert(createConstMissingNode());
}

return constMissingNode.call(frame, module, "const_missing", null, symbolName);
}

@@ -92,4 +114,17 @@ protected CallDispatchHeadNode createConstMissingNode() {
return DispatchHeadNodeFactory.createMethodCall(getContext());
}

protected boolean guardName(String name, String cachedName, ConditionProfile sameNameProfile) {
// This is likely as for literal constant lookup the name does not change and Symbols always return the same String.
if (sameNameProfile.profile(name == cachedName)) {
return true;
} else {
return name.equals(cachedName);
}
}

protected int getCacheLimit() {
return getContext().getOptions().CONSTANT_LOOKUP_CACHE;
}

}
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ public static DynamicObject createClassClass(RubyContext context) {
model.rubyModuleObject = rubyClass;
Layouts.CLASS.setInstanceFactoryUnsafe(rubyClass, factory);
Layouts.MODULE.setFields(rubyClass, model);
model.name = model.givenBaseName;
model.setFullName(model.givenBaseName);

assert RubyGuards.isRubyModule(rubyClass);
assert RubyGuards.isRubyClass(rubyClass);
@@ -73,7 +73,7 @@ public static DynamicObject createBootClass(RubyContext context, DynamicObject c
model.rubyModuleObject = rubyClass;

if (model.lexicalParent == null) { // bootstrap or anonymous module
Layouts.MODULE.getFields(rubyClass).name = Layouts.MODULE.getFields(rubyClass).givenBaseName;
Layouts.MODULE.getFields(rubyClass).setFullName(Layouts.MODULE.getFields(rubyClass).givenBaseName);
} else {
Layouts.MODULE.getFields(rubyClass).getAdoptedByLexicalParent(context, model.lexicalParent, model.givenBaseName, null);
}
@@ -115,10 +115,10 @@ public static DynamicObject createRubyClass(RubyContext context, DynamicObject c

model.rubyModuleObject = rubyClass;

if (model.lexicalParent == null) { // bootstrap or anonymous module
Layouts.MODULE.getFields(rubyClass).name = Layouts.MODULE.getFields(rubyClass).givenBaseName;
} else {
if (model.lexicalParent != null) {
Layouts.MODULE.getFields(rubyClass).getAdoptedByLexicalParent(context, model.lexicalParent, model.givenBaseName, null);
} else if (Layouts.MODULE.getFields(rubyClass).givenBaseName != null) { // bootstrap module
Layouts.MODULE.getFields(rubyClass).setFullName(Layouts.MODULE.getFields(rubyClass).givenBaseName);
}

if (superclass != null) {
Loading

0 comments on commit 5ed3d47

Please sign in to comment.