Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8b84a83d1cf3
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f7773002336c
Choose a head ref
  • 6 commits
  • 17 files changed
  • 1 contributor

Commits on Dec 30, 2014

  1. Copy the full SHA
    2bbab49 View commit details
  2. Copy the full SHA
    0df0bbb View commit details
  3. Depollute LOADED_FEATURES.

    * enumerator.jar, complex.jar, rational.jar are now "provided" as
      faux already-required libraries.
    * Do the same for jruby.jar and java.jar, standard since 1.7.
    headius committed Dec 30, 2014
    Copy the full SHA
    28f5506 View commit details
  4. Copy the full SHA
    46ea95f View commit details
  5. Copy the full SHA
    aa8cbd2 View commit details
  6. Allow Symbols to GC.

    This is a somewhat naïve change, but it appears to maintain a
    stable memory profile during the following code:
    
    ```ruby
    i = 0; loop { i.to_sym; i+=1 }
    ```
    
    It also passes test:mri, test:jruby, and spec:ruby locally.
    
    Could it really be this easy?
    headius committed Dec 30, 2014
    Copy the full SHA
    f777300 View commit details
27 changes: 8 additions & 19 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@

import org.jruby.compiler.Constantizable;
import org.jruby.compiler.NotCompilableException;
import org.jruby.ext.jruby.JRubyLibrary;
import org.jruby.ir.IRScriptBody;
import org.jruby.parser.StaticScope;
import org.objectweb.asm.util.TraceClassVisitor;
@@ -73,7 +74,6 @@
import org.jruby.ext.ffi.FFI;
import org.jruby.ext.fiber.ThreadFiber;
import org.jruby.ext.fiber.ThreadFiberLibrary;
import org.jruby.ext.jruby.JRubyConfigLibrary;
import org.jruby.ext.tracepoint.TracePoint;
import org.jruby.internal.runtime.GlobalVariables;
import org.jruby.internal.runtime.ThreadService;
@@ -1538,9 +1538,6 @@ private void initCore() {
new ThreadFiberLibrary().load(this, false);

TracePoint.createTracePointClass(this);

// Load the JRuby::Config module for accessing configuration settings from Ruby
new JRubyConfigLibrary().load(this, false);
}

public static final int NIL_PREFILLED_ARRAY_SIZE = RubyArray.ARRAY_DEFAULT_SIZE * 8;
@@ -1722,21 +1719,13 @@ private void initBuiltins() {
addLazyBuiltin("coverage.jar", "coverage", "org.jruby.ext.coverage.CoverageLibrary");

// TODO: implement something for these?
Library dummy = new Library() {
public void load(Ruby runtime, boolean wrap) throws IOException {
// dummy library that does nothing right now
}
};
addBuiltinIfAllowed("continuation.rb", dummy);
addBuiltinIfAllowed("io/nonblock.rb", dummy);

// rb_provide logic, in a roundabout way
addLazyBuiltin("enumerator.jar", "enumerator", "org.jruby.ext.enumerator.EnumeratorLibrary");
loadService.require("enumerator.jar");
addBuiltinIfAllowed("rational.jar", dummy);
loadService.require("rational.jar");
addBuiltinIfAllowed("complex.jar", dummy);
loadService.require("complex.jar");
addBuiltinIfAllowed("continuation.rb", Library.DUMMY);
addBuiltinIfAllowed("io/nonblock.rb", Library.DUMMY);

// for backward compatibility
loadService.provide("enumerator.jar"); // can't be in RubyEnumerator because LoadService isn't ready then
loadService.provide("rational.jar");
loadService.provide("complex.jar");

if(RubyInstanceConfig.NATIVE_NET_PROTOCOL) {
addLazyBuiltin("net/protocol.rb", "net/protocol", "org.jruby.ext.net.protocol.NetProtocolBufferedIOLibrary");
129 changes: 95 additions & 34 deletions core/src/main/java/org/jruby/RubySymbol.java
Original file line number Diff line number Diff line change
@@ -62,6 +62,7 @@
import org.jruby.util.PerlHash;
import org.jruby.util.SipHashInline;

import java.lang.ref.WeakReference;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

@@ -641,7 +642,7 @@ public static final class SymbolTable {

private final ReentrantLock tableLock = new ReentrantLock();
private volatile SymbolEntry[] symbolTable;
private final ConcurrentHashMap<ByteList, RubySymbol> bytelistTable = new ConcurrentHashMap<ByteList, RubySymbol>(100, 0.75f, Runtime.getRuntime().availableProcessors());
private final ConcurrentHashMap<ByteList, WeakReference<RubySymbol>> bytelistTable = new ConcurrentHashMap<ByteList, WeakReference<RubySymbol>>(100, 0.75f, Runtime.getRuntime().availableProcessors());
private int size;
private int threshold;
private final float loadFactor;
@@ -660,30 +661,44 @@ public SymbolTable(Ruby runtime) {
static class SymbolEntry {
final int hash;
final String name;
final RubySymbol symbol;
final WeakReference<RubySymbol> symbol;
final SymbolEntry next;

SymbolEntry(int hash, String name, RubySymbol symbol, SymbolEntry next) {
this.hash = hash;
this.name = name;
this.symbol = symbol;
this.symbol = new WeakReference(symbol);
this.next = next;
}
}

public RubySymbol getSymbol(String name) {
int hash = name.hashCode();
SymbolEntry[] table = symbolTable;
RubySymbol symbol = null;

for (SymbolEntry e = getEntryFromTable(table, hash); e != null; e = e.next) {
if (isSymbolMatch(name, hash, e)) return e.symbol;
if (isSymbolMatch(name, hash, e)) {
symbol = e.symbol.get();
if (symbol == null) {
// FIXME: remove weak entry?
}
break;
}
}

return createSymbol(name, symbolBytesFromString(runtime, name), hash, table);
if (symbol == null) symbol = createSymbol(name, symbolBytesFromString(runtime, name), hash, table);

return symbol;
}

public RubySymbol getSymbol(ByteList bytes) {
RubySymbol symbol = bytelistTable.get(bytes);
RubySymbol symbol = null;
WeakReference<RubySymbol> symbolRef = bytelistTable.get(bytes);
if (symbolRef != null) {
symbol = symbolRef.get();
}

if (symbol != null) return symbol;

String name = bytes.toString();
@@ -692,7 +707,10 @@ public RubySymbol getSymbol(ByteList bytes) {

for (SymbolEntry e = getEntryFromTable(table, hash); e != null; e = e.next) {
if (isSymbolMatch(name, hash, e)) {
symbol = e.symbol;
symbol = e.symbol.get();
if (symbol == null) {
// FIXME: remove weak entry?
}
break;
}
}
@@ -701,19 +719,30 @@ public RubySymbol getSymbol(ByteList bytes) {
symbol = createSymbol(name, bytes, hash, table);
}

bytelistTable.put(bytes, symbol);
bytelistTable.put(bytes, new WeakReference<RubySymbol>(symbol));

return symbol;
}

public RubySymbol fastGetSymbol(String internedName) {
SymbolEntry[] table = symbolTable;
RubySymbol symbol = null;

for (SymbolEntry e = getEntryFromTable(symbolTable, internedName.hashCode()); e != null; e = e.next) {
if (isSymbolMatch(internedName, e)) return e.symbol;
if (isSymbolMatch(internedName, e)) {
symbol = e.symbol.get();
if (symbol == null) {
// FIXME: remove weak entry?
}
break;
}
}

return fastCreateSymbol(internedName, table);
if (symbol == null) {
symbol = fastCreateSymbol(internedName, table);
}

return symbol;
}

private static SymbolEntry getEntryFromTable(SymbolEntry[] table, int hash) {
@@ -734,19 +763,28 @@ private RubySymbol createSymbol(String name, ByteList value, int hash, SymbolEnt
try {
int index;
int potentialNewSize = size + 1;

RubySymbol symbol = null;

table = potentialNewSize > threshold ? rehash() : symbolTable;

// try lookup again under lock
for (SymbolEntry e = table[index = hash & (table.length - 1)]; e != null; e = e.next) {
if (hash == e.hash && name.equals(e.name)) return e.symbol;
if (hash == e.hash && name.equals(e.name)) {
symbol = e.symbol.get();
if (symbol == null) {
// FIXME: remove weak entry?
}
break;
}
}
if (symbol == null) {
String internedName = name.intern();
symbol = new RubySymbol(runtime, internedName, value);
table[index] = new SymbolEntry(hash, internedName, symbol, table[index]);
size = potentialNewSize;
// write-volatile
symbolTable = table;
}
String internedName = name.intern();
RubySymbol symbol = new RubySymbol(runtime, internedName, value);
table[index] = new SymbolEntry(hash, internedName, symbol, table[index]);
size = potentialNewSize;
// write-volatile
symbolTable = table;
return symbol;
} finally {
lock.unlock();
@@ -760,18 +798,27 @@ private RubySymbol fastCreateSymbol(String internedName, SymbolEntry[] table) {
int index;
int hash;
int potentialNewSize = size + 1;

table = potentialNewSize > threshold ? rehash() : symbolTable;
RubySymbol symbol = null;

table = potentialNewSize > threshold ? rehash() : symbolTable;

// try lookup again under lock
for (SymbolEntry e = table[index = (hash = internedName.hashCode()) & (table.length - 1)]; e != null; e = e.next) {
if (internedName == e.name) return e.symbol;
if (internedName == e.name) {
symbol = e.symbol.get();
if (symbol == null) {
// FIXME: remove weak entry?
}
break;
}
}
if (symbol == null) {
symbol = new RubySymbol(runtime, internedName);
table[index] = new SymbolEntry(hash, internedName, symbol, table[index]);
size = potentialNewSize;
// write-volatile
symbolTable = table;
}
RubySymbol symbol = new RubySymbol(runtime, internedName);
table[index] = new SymbolEntry(hash, internedName, symbol, table[index]);
size = potentialNewSize;
// write-volatile
symbolTable = table;
return symbol;
} finally {
lock.unlock();
@@ -782,20 +829,29 @@ private RubySymbol fastCreateSymbol(String internedName, SymbolEntry[] table) {
public RubySymbol lookup(String name) {
int hash = name.hashCode();
SymbolEntry[] table;
RubySymbol symbol = null;

for (SymbolEntry e = (table = symbolTable)[hash & (table.length - 1)]; e != null; e = e.next) {
if (hash == e.hash && name.equals(e.name)) return e.symbol;
if (hash == e.hash && name.equals(e.name)) {
symbol = e.symbol.get();
if (symbol == null) {
// FIXME: remove weak entry?
}
break;
}
}

return null;
return symbol;
}

public RubySymbol lookup(long id) {
SymbolEntry[] table = symbolTable;
RubySymbol symbol = null;

for (int i = table.length; --i >= 0; ) {
for (SymbolEntry e = table[i]; e != null; e = e.next) {
if (id == e.symbol.id) return e.symbol;
symbol = e.symbol.get();
if (symbol != null && id == symbol.id) return symbol;
}
}

@@ -805,10 +861,12 @@ public RubySymbol lookup(long id) {
public RubyArray all_symbols() {
SymbolEntry[] table = this.symbolTable;
RubyArray array = runtime.newArray(this.size);

RubySymbol symbol;

for (int i = table.length; --i >= 0; ) {
for (SymbolEntry e = table[i]; e != null; e = e.next) {
array.append(e.symbol);
symbol = e.symbol.get();
if (symbol != null) array.append(symbol);
}
}
return array;
@@ -861,9 +919,12 @@ private SymbolEntry[] rehash() {

// Clone all remaining nodes
for (SymbolEntry p = e; p != lastRun; p = p.next) {
int k = p.hash & sizeMask;
SymbolEntry n = newTable[k];
newTable[k] = new SymbolEntry(p.hash, p.name, p.symbol, n);
RubySymbol symbol = p.symbol.get();
if (symbol != null) {
int k = p.hash & sizeMask;
SymbolEntry n = newTable[k];
newTable[k] = new SymbolEntry(p.hash, p.name, symbol, n);
}
}
}
}
25 changes: 21 additions & 4 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
@@ -730,14 +730,31 @@ public static IRubyObject pass(IRubyObject recv) {
boolean critical = ts.getCritical();

ts.setCritical(false);

Thread.yield();

ts.setCritical(critical);

try {
Thread.yield();
} finally {
ts.setCritical(critical);
}

return recv.getRuntime().getNil();
}

@JRubyMethod(meta = true)
public static IRubyObject exclusive(ThreadContext context, IRubyObject recv, Block block) {
Ruby runtime = context.runtime;
ThreadService ts = runtime.getThreadService();
boolean critical = ts.getCritical();

ts.setCritical(true);

try {
return block.yieldSpecific(context);
} finally {
ts.setCritical(critical);
}
}

@JRubyMethod(meta = true)
public static RubyArray list(IRubyObject recv) {
RubyThread[] activeThreads = recv.getRuntime().getThreadService().getActiveRubyThreads();
45 changes: 0 additions & 45 deletions core/src/main/java/org/jruby/ext/enumerator/EnumeratorLibrary.java

This file was deleted.

52 changes: 0 additions & 52 deletions core/src/main/java/org/jruby/ext/jruby/JRubyConfigLibrary.java

This file was deleted.

14 changes: 12 additions & 2 deletions core/src/main/java/org/jruby/ext/jruby/JRubyLibrary.java
Original file line number Diff line number Diff line change
@@ -73,6 +73,7 @@
public class JRubyLibrary implements Library {
public void load(Ruby runtime, boolean wrap) {
ThreadContext context = runtime.getCurrentContext();

runtime.getLoadService().require("java");

// load Ruby parts of the 'jruby' library
@@ -89,8 +90,17 @@ public void load(Ruby runtime, boolean wrap) {

RubyClass fiberLocalClass = jrubyModule.defineClassUnder("FiberLocal", runtime.getObject(), JRubyFiberLocal.ALLOCATOR);
fiberLocalClass.defineAnnotatedMethods(JRubyExecutionContextLocal.class);

new JRubyConfigLibrary().load(runtime, wrap);

RubyModule config = jrubyModule.defineModuleUnder("CONFIG");
config.getSingletonClass().defineAnnotatedMethods(JRubyConfig.class);
}

public static class JRubyConfig {
@JRubyMethod(name = "rubygems_disabled?")
public static IRubyObject rubygems_disabled_p(ThreadContext context, IRubyObject self) {
return context.runtime.newBoolean(
context.runtime.getInstanceConfig().isDisableGems());
}
}

/**
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/ir/interpreter/Interpreter.java
Original file line number Diff line number Diff line change
@@ -590,10 +590,10 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
private static void extractToMethodToAvoidC2Crash(ThreadContext context, Instr instr, Throwable t) {
if (!(t instanceof Unrescuable)) {
if (!instr.canRaiseException()) {
System.err.println("ERROR: Got exception " + t + " but instr " + instr + " is not supposed to be raising exceptions!");
System.err.println("BUG: Got exception " + t + " but instr " + instr + " is not supposed to be raising exceptions!");
}
if ((t instanceof RaiseException) && context.runtime.getGlobalVariables().get("$!") != IRRuntimeHelpers.unwrapRubyException(t)) {
System.err.println("ERROR: $! and exception are not matching up.");
System.err.println("BUG: $! and exception are not matching up.");
System.err.println("$!: " + context.runtime.getGlobalVariables().get("$!"));
System.err.println("t : " + t);
}
5 changes: 3 additions & 2 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -109,13 +109,14 @@ public class Java implements Library {
public static final boolean NEW_STYLE_EXTENSION = Options.JI_NEWSTYLEEXTENSION.load();
public static final boolean OBJECT_PROXY_CACHE = Options.JI_OBJECTPROXYCACHE.load();

public void load(Ruby runtime, boolean wrap) throws IOException {
public void load(Ruby runtime, boolean wrap) {
createJavaModule(runtime);

RubyModule jpmt = runtime.defineModule("JavaPackageModuleTemplate");
jpmt.getSingletonClass().setSuperClass(new BlankSlateWrapper(runtime, jpmt.getMetaClass().getSuperClass(), runtime.getKernel()));

runtime.getLoadService().require("jruby/java");
// load Ruby parts of the 'java' library
runtime.getLoadService().load("jruby/java.rb", false);

// rewite ArrayJavaProxy superclass to point at Object, so it inherits Object behaviors
RubyClass ajp = runtime.getClass("ArrayJavaProxy");
5 changes: 5 additions & 0 deletions core/src/main/java/org/jruby/runtime/load/Library.java
Original file line number Diff line number Diff line change
@@ -33,5 +33,10 @@
import org.jruby.Ruby;

public interface Library {
public static final Library DUMMY = new Library() {
public void load(Ruby runtime, boolean wrap) throws IOException {
// dummy library that does nothing right now
}
};
void load(Ruby runtime, boolean wrap) throws IOException;
}
6 changes: 6 additions & 0 deletions core/src/main/java/org/jruby/runtime/load/LoadService.java
Original file line number Diff line number Diff line change
@@ -270,6 +270,12 @@ public void addPaths(String... additionalDirectories) {
addPath(dir);
}
}

// MRI: rb_provide, roughly
public void provide(String library) {
addBuiltinLibrary(library, Library.DUMMY);
addLoadedFeature(library, library);
}

protected boolean isFeatureInIndex(String shortName) {
return loadedFeaturesIndex.containsKey(shortName);
11 changes: 6 additions & 5 deletions core/src/main/ruby/jruby/java.rb
Original file line number Diff line number Diff line change
@@ -33,9 +33,10 @@
# the terms of any one of the EPL, the GPL or the LGPL.
###### END LICENSE BLOCK ######

require 'jruby/java/java_module'
require 'jruby/java/java_package_module_template'
require 'jruby/java/java_utilities'
# These are loads so they don't pollute LOADED_FEATURES
load 'jruby/java/java_module.rb'
load 'jruby/java/java_package_module_template.rb'
load 'jruby/java/java_utilities.rb'

require 'jruby/java/core_ext'
require 'jruby/java/java_ext'
load 'jruby/java/core_ext.rb'
load 'jruby/java/java_ext.rb'
7 changes: 4 additions & 3 deletions core/src/main/ruby/jruby/java/core_ext.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Extensions to Ruby classes

require 'jruby/java/core_ext/module'
require 'jruby/java/core_ext/object'
require 'jruby/java/core_ext/kernel'
# These are loads so they don't pollute LOADED_FEATURES
load 'jruby/java/core_ext/module.rb'
load 'jruby/java/core_ext/object.rb'
load 'jruby/java/core_ext/kernel.rb'
11 changes: 6 additions & 5 deletions core/src/main/ruby/jruby/java/java_ext.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Extensions to Java classes

require 'jruby/java/java_ext/java.lang'
require 'jruby/java/java_ext/java.util'
require 'jruby/java/java_ext/java.util.regex'
require 'jruby/java/java_ext/java.io'
require 'jruby/java/java_ext/java.net'
# These are loads so they don't pollute LOADED_FEATURES
load 'jruby/java/java_ext/java.lang.rb'
load 'jruby/java/java_ext/java.util.rb'
load 'jruby/java/java_ext/java.util.regex.rb'
load 'jruby/java/java_ext/java.io.rb'
load 'jruby/java/java_ext/java.net.rb'
2 changes: 0 additions & 2 deletions core/src/main/ruby/jruby/jruby.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'java'

module JRuby
def self.init_asm
begin
3 changes: 0 additions & 3 deletions core/src/main/ruby/jruby/kernel.rb
Original file line number Diff line number Diff line change
@@ -20,10 +20,7 @@
end
end

require 'thread.jar'

# These are loads so they don't pollute LOADED_FEATURES
load 'jruby/kernel/thread.rb'
load 'jruby/kernel/kernel.rb'
load 'jruby/kernel/proc.rb'
load 'jruby/kernel/process.rb'
10 changes: 0 additions & 10 deletions core/src/main/ruby/jruby/kernel/thread.rb

This file was deleted.

1 change: 1 addition & 0 deletions rakelib/test.rake
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ end
namespace :test do
desc "Compile test code"
task :compile do
mkdir_p "test/target/test-classes"
sh "javac -cp lib/jruby.jar:test/target/junit.jar -d test/target/test-classes #{Dir['spec/java_integration/fixtures/**/*.java'].to_a.join(' ')}"
end