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: e3719954b9d5
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6fb60a4cad2b
Choose a head ref
  • 7 commits
  • 13 files changed
  • 2 contributors

Commits on Apr 23, 2015

  1. Use jnr-ffi 2.0.3 to gain ppc64le support.

    jnr/jnr-ffi#40 and related issues.
    headius committed Apr 23, 2015
    Copy the full SHA
    4752304 View commit details

Commits on Apr 24, 2015

  1. Copy the full SHA
    f7b8a8a View commit details
  2. 1
    Copy the full SHA
    2bdfb5a View commit details
  3. Copy the full SHA
    f7d09d0 View commit details
  4. Use jnr-ffi 2.0.3 to gain ppc64le support.

    jnr/jnr-ffi#40 and related issues.
    headius committed Apr 24, 2015
    Copy the full SHA
    c815260 View commit details
  5. Merge remote-tracking branch 'origin/jruby-1_7'

    Conflicts:
    	core/src/main/java/org/jruby/javasupport/JavaSupport.java
    	core/src/main/java/org/jruby/javasupport/binding/Initializer.java
    	core/src/main/java/org/jruby/javasupport/binding/InterfaceInitializer.java
    headius committed Apr 24, 2015
    Copy the full SHA
    a1cb409 View commit details
  6. Revert "remove more jruby.home properties from build"

    This reverts commit 46f43bb.
    headius committed Apr 24, 2015
    Copy the full SHA
    6fb60a4 View commit details
1 change: 1 addition & 0 deletions core/pom.rb
Original file line number Diff line number Diff line change
@@ -214,6 +214,7 @@
'reuseForks' => 'false',
'systemProperties' => {
'jruby.compat.version' => '1.9',
'jruby.home' => '${basedir}/..'
},
'argLine' => '-Xmx${jruby.test.memory} -XX:MaxPermSize=${jruby.test.memory.permgen} -Dfile.encoding=UTF-8 -Djava.awt.headless=true',
'includes' => [ 'org/jruby/test/MainTestSuite.java',
2 changes: 2 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -116,6 +116,7 @@
<groupId>com.github.jnr</groupId>
<artifactId>jnr-ffi</artifactId>
<version>2.0.3-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
@@ -509,6 +510,7 @@
<reuseForks>false</reuseForks>
<systemProperties>
<jruby.compat.version>1.9</jruby.compat.version>
<jruby.home>${basedir}/..</jruby.home>
</systemProperties>
<argLine>-Xmx${jruby.test.memory} -XX:MaxPermSize=${jruby.test.memory.permgen} -Dfile.encoding=UTF-8 -Djava.awt.headless=true</argLine>
<includes>
92 changes: 53 additions & 39 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -439,50 +439,71 @@ public static RubyModule getProxyClass(Ruby runtime, JavaClass javaClass) {
}

public static RubyModule getProxyClass(final Ruby runtime, final Class<?> clazz) {
RubyModule unfinished = runtime.getJavaSupport().getUnfinishedProxyClassCache().get(clazz).get();
if (unfinished != null) return unfinished;
RubyModule proxy = runtime.getJavaSupport().getUnfinishedProxy(clazz);
if (proxy != null) return proxy;
return runtime.getJavaSupport().getProxyClassFromCache(clazz);
}

// Only used by proxy ClassValue calculator in JavaSupport
static RubyModule createProxyClassForClass(final Ruby runtime, final Class<?> clazz) {
final JavaSupport javaSupport = runtime.getJavaSupport();

if (clazz.isInterface()) return generateInterfaceProxy(runtime, clazz);

return generateClassProxy(runtime, clazz, javaSupport);
}
RubyModule proxy;
RubyClass superClass = null;
if (clazz.isInterface()) {
proxy = (RubyModule) runtime.getJavaSupport().getJavaInterfaceTemplate().dup();
} else {
if (clazz.isArray()) {
superClass = javaSupport.getArrayProxyClass();
} else if (clazz.isPrimitive()) {
superClass = javaSupport.getConcreteProxyClass();
} else if (clazz == Object.class) {
superClass = javaSupport.getConcreteProxyClass();
} else {
// other java proxy classes added under their superclass' java proxy
superClass = (RubyClass) getProxyClass(runtime, clazz.getSuperclass());
}
proxy = RubyClass.newClass(runtime, superClass);
}

private static RubyModule generateInterfaceProxy(final Ruby runtime, final Class javaClass) {
if (!javaClass.isInterface()) {
throw runtime.newArgumentError(javaClass.toString() + " is not an interface");
// ensure proxy is visible down-thread
javaSupport.beginProxy(clazz, proxy);
try {
if (clazz.isInterface()) {
generateInterfaceProxy(runtime, clazz, proxy);
} else {
generateClassProxy(runtime, clazz, (RubyClass)proxy, superClass, javaSupport);
}
} finally {
javaSupport.endProxy(clazz);
}

RubyModule proxyModule = (RubyModule) runtime.getJavaSupport().getJavaInterfaceTemplate().dup();
return proxy;
}

private static void generateInterfaceProxy(final Ruby runtime, final Class javaClass, final RubyModule proxy) {
assert javaClass.isInterface() : "not an interface: " + javaClass;

// include any interfaces we extend
final Class<?>[] extended = javaClass.getInterfaces();
for ( int i = extended.length; --i >= 0; ) {
for (int i = extended.length; --i >= 0; ) {
RubyModule extModule = getInterfaceModule(runtime, extended[i]);
proxyModule.includeModule(extModule);
proxy.includeModule(extModule);
}
Initializer.setupProxyModule(runtime, javaClass, proxyModule);
addToJavaPackageModule(proxyModule);

return proxyModule;
Initializer.setupProxyModule(runtime, javaClass, proxy);
addToJavaPackageModule(proxy);
}

private static RubyModule generateClassProxy(Ruby runtime, Class<?> clazz, JavaSupport javaSupport) {
RubyModule proxyClass;
private static void generateClassProxy(Ruby runtime, Class<?> clazz, RubyClass proxy, RubyClass superClass, JavaSupport javaSupport) {
if (clazz.isArray()) {
proxyClass = createProxyClass(runtime, javaSupport.getArrayProxyClass(), clazz, true);
createProxyClass(runtime, proxy, clazz, true);

// FIXME: Organizationally this might be nicer in a specialized class
if ( clazz.getComponentType() == byte.class ) {
final Encoding ascii8bit = runtime.getEncodingService().getAscii8bitEncoding();

// All bytes can be considered raw strings and forced to particular codings if not 8bitascii
proxyClass.addMethod("to_s", new JavaMethodZero(proxyClass, PUBLIC) {
proxy.addMethod("to_s", new JavaMethodZero(proxy, PUBLIC) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
ByteList bytes = new ByteList((byte[]) ((ArrayJavaProxy) self).getObject(), ascii8bit);
@@ -492,55 +513,48 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
}
}
else if ( clazz.isPrimitive() ) {
proxyClass = createProxyClass(runtime, javaSupport.getConcreteProxyClass(), clazz, true);
createProxyClass(runtime, proxy, clazz, true);
}
else if ( clazz == Object.class ) {
// java.lang.Object is added at root of java proxy classes
proxyClass = createProxyClass(runtime, javaSupport.getConcreteProxyClass(), clazz, true);
createProxyClass(runtime, proxy, clazz, true);
if (NEW_STYLE_EXTENSION) {
proxyClass.getMetaClass().defineAnnotatedMethods(NewStyleExtensionInherited.class);
proxy.getMetaClass().defineAnnotatedMethods(NewStyleExtensionInherited.class);
} else {
proxyClass.getMetaClass().defineAnnotatedMethods(OldStyleExtensionInherited.class);
proxy.getMetaClass().defineAnnotatedMethods(OldStyleExtensionInherited.class);
}
addToJavaPackageModule(proxyClass);
addToJavaPackageModule(proxy);
}
else {
// other java proxy classes added under their superclass' java proxy
RubyClass superProxyClass = (RubyClass) getProxyClass(runtime, clazz.getSuperclass());
proxyClass = createProxyClass(runtime, superProxyClass, clazz, false);
createProxyClass(runtime, proxy, clazz, false);
// include interface modules into the proxy class
final Class<?>[] interfaces = clazz.getInterfaces();
for ( int i = interfaces.length; --i >= 0; ) {
proxyClass.includeModule(getInterfaceModule(runtime, interfaces[i]));
proxy.includeModule(getInterfaceModule(runtime, interfaces[i]));
}
if ( Modifier.isPublic(clazz.getModifiers()) ) {
addToJavaPackageModule(proxyClass);
addToJavaPackageModule(proxy);
}
}

// JRUBY-1000, fail early when attempting to subclass a final Java class;
// solved here by adding an exception-throwing "inherited"
if ( Modifier.isFinal(clazz.getModifiers()) ) {
final String clazzName = clazz.getCanonicalName();
proxyClass.getMetaClass().addMethod("inherited", new org.jruby.internal.runtime.methods.JavaMethod(proxyClass, PUBLIC) {
proxy.getMetaClass().addMethod("inherited", new org.jruby.internal.runtime.methods.JavaMethod(proxy, PUBLIC) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
throw context.runtime.newTypeError("can not extend final Java class: " + clazzName);
}
});
}

return proxyClass;
}

private static RubyClass createProxyClass(final Ruby runtime,
final RubyClass baseType, final Class<?> javaClass, boolean invokeInherited) {
RubyClass proxyClass;
final RubyClass proxyClass, final Class<?> javaClass, boolean invokeInherited) {

// this needs to be split, since conditional calling #inherited doesn't fit standard ruby semantics
final RubyClass superClass = proxyClass.getSuperClass();

final RubyClass superClass = baseType;
proxyClass = RubyClass.newClass(runtime, superClass);
proxyClass.makeMetaClass( superClass.getMetaClass() );

if ( Map.class.isAssignableFrom( javaClass ) ) {
@@ -1457,6 +1471,6 @@ private static void addToJavaPackageModule(RubyModule proxyClass, JavaClass java
@Deprecated
private static RubyClass createProxyClass(final Ruby runtime,
final RubyClass baseType, final JavaClass javaClass, boolean invokeInherited) {
return createProxyClass(runtime, baseType, javaClass.javaClass(), invokeInherited);
return createProxyClass(runtime, RubyClass.newClass(runtime, baseType), javaClass, invokeInherited);
}
}
8 changes: 6 additions & 2 deletions core/src/main/java/org/jruby/javasupport/JavaSupport.java
Original file line number Diff line number Diff line change
@@ -107,9 +107,13 @@ public abstract class JavaSupport {

public abstract Map<Set<?>, JavaProxyClass> getJavaProxyClassCache();

public abstract ClassValue<ThreadLocal<RubyModule>> getUnfinishedProxyClassCache();

public abstract ClassValue<Map<String, AssignedName>> getStaticAssignedNames();

public abstract ClassValue<Map<String, AssignedName>> getInstanceAssignedNames();

public abstract void beginProxy(Class cls, RubyModule proxy);

public abstract void endProxy(Class cls);

public abstract RubyModule getUnfinishedProxy(Class cls);
}
71 changes: 46 additions & 25 deletions core/src/main/java/org/jruby/javasupport/JavaSupportImpl.java
Original file line number Diff line number Diff line change
@@ -33,45 +33,49 @@
***** END LICENSE BLOCK *****/
package org.jruby.javasupport;

import org.jruby.javasupport.binding.AssignedName;
import org.jruby.util.collections.MapBasedClassValue;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.exceptions.RaiseException;
import org.jruby.exceptions.Unrescuable;
import org.jruby.util.collections.ClassValue;
import org.jruby.javasupport.binding.AssignedName;
import org.jruby.javasupport.proxy.JavaProxyClass;
import org.jruby.javasupport.util.ObjectProxyCache;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.WeakIdentityHashMap;
import org.jruby.util.cli.Options;
import org.jruby.util.collections.ClassValueCalculator;

public class JavaSupportImpl extends JavaSupport {
private final Ruby runtime;

private final ObjectProxyCache<IRubyObject,RubyClass> objectProxyCache =
// TODO: specifying soft refs, may want to compare memory consumption,
// behavior with weak refs (specify WEAK in place of SOFT below)
new ObjectProxyCache<IRubyObject,RubyClass>(ObjectProxyCache.ReferenceType.WEAK) {
// TODO: specifying soft refs, may want to compare memory consumption,
// behavior with weak refs (specify WEAK in place of SOFT below)
new ObjectProxyCache<IRubyObject,RubyClass>(ObjectProxyCache.ReferenceType.WEAK) {

public IRubyObject allocateProxy(Object javaObject, RubyClass clazz) {
return Java.allocateProxy(javaObject, clazz);
}
};
public IRubyObject allocateProxy(Object javaObject, RubyClass clazz) {
return Java.allocateProxy(javaObject, clazz);
}
};

private final ClassValue<JavaClass> javaClassCache;
private final ClassValue<RubyModule> proxyClassCache;
private final ClassValue<ThreadLocal<RubyModule>> unfinishedProxyClassCache;
private class UnfinishedProxy extends ReentrantLock {
volatile RubyModule proxy;
UnfinishedProxy(RubyModule proxy) {
this.proxy = proxy;
}
}
private final Map<Class, UnfinishedProxy> unfinishedProxies;
private final ClassValue<Map<String, AssignedName>> staticAssignedNames;
private final ClassValue<Map<String, AssignedName>> instanceAssignedNames;

@@ -108,19 +112,20 @@ public JavaClass computeValue(Class<?> cls) {
return new JavaClass(runtime, cls);
}
});

this.proxyClassCache = ClassValue.newInstance(new ClassValueCalculator<RubyModule>() {
/**
* Because of the complexity of processing a given class and all its dependencies,
* we opt to synchronize this logic. Creation of all proxies goes through here,
* allowing us to skip some threading work downstream.
*/
@Override
public RubyModule computeValue(Class<?> cls) {
public synchronized RubyModule computeValue(Class<?> cls) {
return Java.createProxyClassForClass(runtime, cls);
}
});
this.unfinishedProxyClassCache = ClassValue.newInstance(new ClassValueCalculator<ThreadLocal<RubyModule>>() {
@Override
public ThreadLocal<RubyModule> computeValue(Class<?> cls) {
return new ThreadLocal<RubyModule>();
}
});
this.staticAssignedNames =ClassValue.newInstance(new ClassValueCalculator<Map<String, AssignedName>>() {

this.staticAssignedNames = ClassValue.newInstance(new ClassValueCalculator<Map<String, AssignedName>>() {
@Override
public Map<String, AssignedName> computeValue(Class<?> cls) {
return new HashMap<String, AssignedName>();
@@ -132,6 +137,9 @@ public Map<String, AssignedName> computeValue(Class<?> cls) {
return new HashMap<String, AssignedName>();
}
});

// Proxy creation is synchronized (see above) so a HashMap is fine for recursion detection.
this.unfinishedProxies = new ConcurrentHashMap<Class, UnfinishedProxy>(8, 0.75f, 1);
}

public Class loadJavaClass(String className) throws ClassNotFoundException {
@@ -331,10 +339,6 @@ public Map<Set<?>, JavaProxyClass> getJavaProxyClassCache() {
return this.javaProxyClassCache;
}

public ClassValue<ThreadLocal<RubyModule>> getUnfinishedProxyClassCache() {
return unfinishedProxyClassCache;
}

public ClassValue<Map<String, AssignedName>> getStaticAssignedNames() {
return staticAssignedNames;
}
@@ -343,6 +347,23 @@ public ClassValue<Map<String, AssignedName>> getInstanceAssignedNames() {
return instanceAssignedNames;
}

public void beginProxy(Class cls, RubyModule proxy) {
UnfinishedProxy up = new UnfinishedProxy(proxy);
up.lock();
unfinishedProxies.put(cls, up);
}

public void endProxy(Class cls) {
UnfinishedProxy up = unfinishedProxies.remove(cls);
up.unlock();
}

public RubyModule getUnfinishedProxy(Class cls) {
UnfinishedProxy up = unfinishedProxies.get(cls);
if (up != null && up.isHeldByCurrentThread()) return up.proxy;
return null;
}

@Deprecated
private volatile Map<Object, Object[]> javaObjectVariables;

Original file line number Diff line number Diff line change
@@ -30,8 +30,6 @@ public RubyModule initialize(RubyModule proxy) {

proxyClass.setReifiedClass(javaClass);

runtime.getJavaSupport().getUnfinishedProxyClassCache().get(javaClass).set(proxyClass);

if ( javaClass.isArray() || javaClass.isPrimitive() ) {
return proxy;
}
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
import org.jruby.internal.runtime.methods.JavaMethod;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaClass;
import org.jruby.javasupport.JavaSupport;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.Helpers;
@@ -34,6 +35,7 @@
*/
public abstract class Initializer {
protected final Ruby runtime;
protected final JavaSupport javaSupport;
protected final Class javaClass;

private static final Logger LOG = LoggerFactory.getLogger("Initializer");
@@ -68,6 +70,7 @@ public abstract class Initializer {

public Initializer(Ruby runtime, Class javaClass) {
this.runtime = runtime;
this.javaSupport = runtime.getJavaSupport();
this.javaClass = javaClass;
}

Original file line number Diff line number Diff line change
@@ -23,8 +23,6 @@ public InterfaceInitializer(Ruby runtime, Class<?> javaClass) {
public RubyModule initialize(RubyModule proxy) {
final State state = new State(runtime, null);

runtime.getJavaSupport().getUnfinishedProxyClassCache().get(javaClass).set(proxy);

Field[] fields = JavaClass.getDeclaredFields(javaClass);

for (int i = fields.length; --i >= 0; ) {
4 changes: 4 additions & 0 deletions maven/jruby-complete/pom.rb
Original file line number Diff line number Diff line change
@@ -14,6 +14,10 @@
'main.basedir' => '${project.parent.parent.basedir}',
'jruby.complete.home' => '${project.build.outputDirectory}/META-INF/jruby.home' )

unless version =~ /-SNAPSHOT/
properties 'jruby.home' => '${basedir}/../..'
end

scope :provided do
jar 'org.jruby:jruby-core:${project.version}'
jar 'org.jruby:jruby-stdlib:${project.version}'
4 changes: 4 additions & 0 deletions maven/jruby-dist/pom.rb
Original file line number Diff line number Diff line change
@@ -11,6 +11,10 @@
'tesla.dump.readonly' => true,
'main.basedir' => '${project.parent.parent.basedir}' )

unless version =~ /-SNAPSHOT/
properties 'jruby.home' => '${basedir}/../..'
end

# pre-installed gems - not default gems !
gem 'ruby-maven', '3.1.1.0.8', :scope => 'provided'

4 changes: 4 additions & 0 deletions maven/jruby/pom.rb
Original file line number Diff line number Diff line change
@@ -13,6 +13,10 @@
'tesla.dump.readonly' => true,
'main.basedir' => '${project.parent.parent.basedir}' )

unless version =~ /-SNAPSHOT/
properties 'jruby.home' => '${basedir}/../..'
end

jar 'org.jruby:jruby-core:${project.version}'
jar 'org.jruby:jruby-stdlib:${project.version}'

4 changes: 4 additions & 0 deletions pom.rb
Original file line number Diff line number Diff line change
@@ -84,6 +84,10 @@
'test-unit.version' => '3.0.3',
'power_assert.version' => '0.2.3' )

unless version =~ /-SNAPSHOT/
properties 'jruby.home' => '${basedir}/..'
end

modules [ 'truffle', 'core', 'lib' ]

plugin_management do
7 changes: 7 additions & 0 deletions test/jruby/test_higher_javasupport.rb
Original file line number Diff line number Diff line change
@@ -1260,6 +1260,13 @@ def test_null_toString
assert nil == org.jruby.javasupport.test.NullToString.new.to_s
end

def test___jsend! # expected to work (with a deprecation) under 1.7
verbose, $VERBOSE = $VERBOSE, nil
java.lang.Long.new(111).__jsend! :toString
ensure
$VERBOSE = verbose
end

# JRUBY-2277
# kind of a strange place for this test, but the error manifested
# when JI was enabled. the actual bug was a problem in alias_method,