Skip to content

Commit

Permalink
Showing 106 changed files with 827 additions and 658 deletions.
12 changes: 12 additions & 0 deletions core/src/main/java/org/jruby/RubySignal.java
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@

import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
import org.jruby.platform.Platform;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.SignalFacade;
@@ -52,6 +53,17 @@ private final static SignalFacade getSignalFacade() {
}

public static void createSignal(Ruby runtime) {
// We force java.lang.Process et al to load so that JVM's CHLD handler can be
// overwritten by users (jruby/jruby#3283)
if (!Platform.IS_WINDOWS) {
try {
Class.forName("java.lang.Process");
Class.forName("java.lang.UNIXProcess");
} catch (Throwable t) {
// if we can't access Process, other things will fail anyway; ignore for now
}
}

RubyModule mSignal = runtime.defineModule("Signal");

mSignal.defineAnnotatedMethods(RubySignal.class);
89 changes: 69 additions & 20 deletions core/src/main/java/org/jruby/java/dispatch/CallableSelector.java
Original file line number Diff line number Diff line change
@@ -172,7 +172,8 @@ private static <T extends ParameterTypes> T findMatchingCallableForArgs(final Ru
final int procArity;
if ( lastArg instanceof RubyProc ) {
final Method implMethod; final int last = msTypes.length - 1;
if ( last >= 0 && msTypes[last].isInterface() && ( implMethod = getFunctionalInterfaceMethod(msTypes[last]) ) != null ) {
if ( last >= 0 && msTypes[last].isInterface() &&
( implMethod = getFunctionalInterfaceMethod(msTypes[last]) ) != null ) {
mostSpecificArity = implMethod.getParameterTypes().length;
}
procArity = ((RubyProc) lastArg).getBlock().getSignature().arityValue();
@@ -181,34 +182,40 @@ private static <T extends ParameterTypes> T findMatchingCallableForArgs(final Ru
procArity = Integer.MIN_VALUE;
}

OUTER: for ( int c = 1; c < size; c++ ) {
/* OUTER: */
for ( int c = 1; c < size; c++ ) {
final T candidate = candidates.get(c);
final Class<?>[] cTypes = candidate.getParameterTypes();

// TODO still need to handle var-args better Class<?> lastType;
for ( int i = 0; i < msTypes.length; i++ ) {
final Class<?> msType = msTypes[i], cType = cTypes[i];
if ( msType != cType && msType.isAssignableFrom(cType) ) {
mostSpecific = candidate; msTypes = cTypes;
ambiguous = false; continue OUTER;
}

final boolean lastArgProc = procArity != Integer.MIN_VALUE;
final Boolean moreSpecific = moreSpecificTypes(msTypes, cTypes, lastArgProc);
if ( (Object) moreSpecific == Boolean.TRUE ) {
mostSpecific = candidate; msTypes = cTypes;
ambiguous = false; continue /* OUTER */;
}
// none more specific; check for ambiguities
for ( int i = 0; i < msTypes.length; i++ ) {
final Class<?> msType = msTypes[i], cType = cTypes[i];
if ( msType == cType || msType.isAssignableFrom(cType) || cType.isAssignableFrom(msType) ) {
ambiguous = false; continue OUTER;
}
else if ( cType.isPrimitive() && msType.isAssignableFrom(getBoxType(cType)) ) {
ambiguous = false; continue OUTER;
}
else {
ambiguous = true;
else { // if ( (Object) moreSpecific == Boolean.FALSE ) {
// none more specific; check for ambiguities
for ( int i = 0; i < msTypes.length; i++ ) {
// TODO if lastArgProc (and we're not dealing with RubyProc.class)
// then comparing last arg should not be needed, right?
// ... same applies for moreSpecificTypes method ...
final Class<?> msType = msTypes[i], cType = cTypes[i];
if ( msType == cType || msType.isAssignableFrom(cType) || cType.isAssignableFrom(msType) ) {
ambiguous = false; break; // continue OUTER;
}
else if ( cType.isPrimitive() && msType.isAssignableFrom(getBoxType(cType)) ) {
ambiguous = false; break; // continue OUTER;
}
else {
ambiguous = true;
}
}
}

// special handling if we're dealing with Proc#impl :
if ( procArity != Integer.MIN_VALUE ) { // lastArg instanceof RubyProc
if ( lastArgProc ) { // lastArg instanceof RubyProc
// cases such as (both ifaces - differ in arg count) :
// java.io.File#listFiles(java.io.FileFilter) ... accept(File)
// java.io.File#listFiles(java.io.FilenameFilter) ... accept(File, String)
@@ -287,6 +294,48 @@ else if ( procArity < 0 && methodArity >= -(procArity + 1) ) { // *splat that fi
return method;
}

private static Boolean moreSpecificTypes(final Class[] msTypes, final Class[] cTypes,
final boolean lastArgProc) {

final int last = msTypes.length - 1;
int moreSpecific = 0; Class<?> msType, cType;
for ( int i = 0; i < last; i++ ) {
msType = msTypes[i]; cType = cTypes[i];
if ( msType == cType ) ;
else if ( msType.isAssignableFrom(cType) ) {
moreSpecific++; /* continue; */
}
else if ( cType.isAssignableFrom(msType) ) {
moreSpecific--; /* continue; */
}
/* return false; */
}

if ( last >= 0 ) { // last argument :
msType = msTypes[last]; cType = cTypes[last];
if ( lastArgProc ) {
if ( cType.isAssignableFrom(RubyProc.class) ) {
if ( ! msType.isAssignableFrom(RubyProc.class) ) moreSpecific++;
// return moreSpecific > 0;
}
else {
// NOTE: maybe this needs some implMethod arity matching here?
return null; // interface matching logic (can not decide)
}
}
else {
if ( msType == cType ) ;
else if ( msType.isAssignableFrom(cType) ) {
moreSpecific++;
}
else if ( cType.isAssignableFrom(msType) ) {
moreSpecific--;
}
}
}
return moreSpecific > 0 ? Boolean.TRUE : Boolean.FALSE;
}

private static <T extends ParameterTypes> T findMatchingCallableForArgsFallback(final Ruby runtime,
final T[] methods, final IRubyObject... args) {
T method = findCallable(methods, Exact, args);
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
* rights and limitations under the License.
*
* Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -27,7 +27,11 @@
***** END LICENSE BLOCK *****/
package org.jruby.javasupport.proxy;

/** this interface is implemented by proxies generated from a JavaProxyClass */
/**
* Interface is implemented by proxies generated from a JavaProxyClass.
*
* @see JavaProxyClassFactory
*/
public interface InternalJavaProxy {

/**
@@ -40,6 +44,8 @@ public interface InternalJavaProxy {
*/
JavaProxyInvocationHandler ___getInvocationHandler();

final Object[] NO_ARGS = new Object[0];
// NOTE: used in JavaProxyClassFactory indirectly
// ... getStatic(JAVA_PROXY_TYPE, "NO_ARGS", ...)
static final Object[] NO_ARGS = new Object[0];

}
Original file line number Diff line number Diff line change
@@ -197,23 +197,25 @@ private JavaProxyClass generate(ClassLoader loader, String targetClassName,
Field proxy_class = clazz.getDeclaredField(PROXY_CLASS_FIELD_NAME);
proxy_class.setAccessible(true);
return (JavaProxyClass) proxy_class.get(clazz);
} catch (Exception ex) {
}
catch (Exception ex) {
InternalError ie = new InternalError();
ie.initCause(ex);
throw ie;
}
}

private static String targetClassName(final Class clazz) {
private static String targetClassName(final Class<?> clazz) {
// We always prepend an org.jruby.proxy package to the beginning
// because java and javax packages are protected and signed
// jars prevent us generating new classes with those package
// names. See JRUBY-2439.
final String pkgName = proxyPackageName(clazz);
final String fullName = clazz.getName();
int ix = fullName.lastIndexOf('.');
String className = ix == -1 ? fullName : fullName.substring(ix + 1);
return pkgName + '.' + className + "$Proxy" + nextId();
final int idx = fullName.lastIndexOf('.');
String className = idx == -1 ? fullName : fullName.substring(idx + 1);
return proxyPackageName(fullName)
.append('.').append(className)
.append("$Proxy").append(nextId()).toString();
}

private static final Method defineClassMethod;
@@ -266,12 +268,17 @@ private ClassWriter beginProxyClass(final String className,
toInternalClassName(superClass),
interfaceNamesForProxyClass(interfaces));

cw.visitField(Opcodes.ACC_PRIVATE, INVOCATION_HANDLER_FIELD_NAME,
INVOCATION_HANDLER_TYPE.getDescriptor(), null, null).visitEnd();
// private final JavaProxyInvocationHandler __handler;
cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL,
INVOCATION_HANDLER_FIELD_NAME,
INVOCATION_HANDLER_TYPE.getDescriptor(), null, null
).visitEnd();

cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
PROXY_CLASS_FIELD_NAME, PROXY_CLASS_TYPE.getDescriptor(), null,
null).visitEnd();
// private static JavaProxyClass __proxy_class;
cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
PROXY_CLASS_FIELD_NAME,
PROXY_CLASS_TYPE.getDescriptor(), null, null
).visitEnd();

return cw;
}
@@ -282,6 +289,7 @@ private String[] interfaceNamesForProxyClass(final Class[] interfaces) {
for (int i = 0; i < interfaces.length; i++) {
interfaceNames[i] = toInternalClassName(interfaces[i]);
}
// all proxies implement our InternalJavaProxy interface :
interfaceNames[interfaces.length] = toInternalClassName(InternalJavaProxy.class);

return interfaceNames;
@@ -296,8 +304,11 @@ private void generateProxyMethods(Class superClass,
}
}

/**
* @see InternalJavaProxy
*/
private void generateGetInvocationHandler(Type selfType, ClassVisitor cw) {
// make getter for handler
// make getter for handler (due implements InternalJavaProxy)
GeneratorAdapter gh = new GeneratorAdapter(Opcodes.ACC_PUBLIC,
new org.objectweb.asm.commons.Method("___getInvocationHandler",
INVOCATION_HANDLER_TYPE, EMPTY_TYPE_ARRAY), null,
@@ -309,8 +320,11 @@ private void generateGetInvocationHandler(Type selfType, ClassVisitor cw) {
gh.endMethod();
}

/**
* @see InternalJavaProxy
*/
private void generateGetProxyClass(Type selfType, ClassVisitor cw) {
// make getter for proxy class
// make getter for proxy class (due implements InternalJavaProxy)
GeneratorAdapter gpc = new GeneratorAdapter(Opcodes.ACC_PUBLIC,
new org.objectweb.asm.commons.Method("___getProxyClass",
PROXY_CLASS_TYPE, EMPTY_TYPE_ARRAY), null,
@@ -486,6 +500,7 @@ private Class[] generateConstructor(Type selfType, Constructor constructor, Clas

ga.loadThis();
ga.loadArg(superConstructorParameterTypes.length);

ga.putField(selfType, INVOCATION_HANDLER_FIELD_NAME, INVOCATION_HANDLER_TYPE);

// do a void return
@@ -795,11 +810,12 @@ private static String packageName(String clazzName) {
return clazzName.substring(0, idx);
}

private static String proxyPackageName(Class clazz) {
String clazzName = clazz.getName();
int idx = clazzName.lastIndexOf('.');
if ( idx == -1 ) return "org.jruby.proxy";
return "org.jruby.proxy." + clazzName.substring(0, idx);
private static StringBuilder proxyPackageName(final String className) {
final String proxyPackagePrefix = "org.jruby.proxy";
final StringBuilder str = new StringBuilder(proxyPackagePrefix.length() + className.length() + 8);
final int idx = className.lastIndexOf('.');
str.append(proxyPackagePrefix);
return idx == -1 ? str : str.append('.').append(className.substring(0, idx));
}

/**
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
* rights and limitations under the License.
*
* Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -28,17 +28,20 @@

package org.jruby.javasupport.proxy;

import java.lang.reflect.InvocationHandler;

import org.jruby.runtime.builtin.IRubyObject;

/**
* A proxy invocation handler for JRuby.
*
* @see java.lang.reflect.InvocationHandler
*/
public interface JavaProxyInvocationHandler {

IRubyObject getOrig();

/**
* Similar to java.lang.reflect.InvocationHandler
*
* Similar to {@link java.lang.reflect.InvocationHandler}
*
* @param receiver
* @param method
* @param args
26 changes: 14 additions & 12 deletions core/src/main/ruby/jruby/java/core_ext/module.rb
Original file line number Diff line number Diff line change
@@ -7,14 +7,17 @@ class Module
# package will become available in this class/module, unless a constant
# with the same name as a Java class is already defined.
#
def include_package(package_name)
def include_package(package)
package = package.package_name if package.respond_to?(:package_name)

if defined? @included_packages
@included_packages << package_name
@included_packages << package
return
end
@included_packages = [package_name]

@included_packages = [ package ]
@java_aliases ||= {}

def self.const_missing(constant)
real_name = @java_aliases[constant] || constant

@@ -23,7 +26,7 @@ def self.const_missing(constant)

@included_packages.each do |package|
begin
java_class = JavaUtilities.get_java_class(package + '.' + real_name.to_s)
java_class = JavaUtilities.get_java_class("#{package}.#{real_name}")
rescue NameError
# we only rescue NameError, since other errors should bubble out
last_error = $!
@@ -44,20 +47,19 @@ def self.const_missing(constant)
end
end
end

# Imports the package specified by +package_name+, first by trying to scan JAR resources
# for the file in question, and failing that by adding a const_missing hook
# to try that package when constants are missing.
def import(package_name, &b)
def import(package_name, &block)
if package_name.respond_to?(:java_class) || (String === package_name && package_name.split(/\./).last =~ /^[A-Z]/)
return super(package_name, &b)
return super(package_name, &block)
end

package_name = package_name.package_name if package_name.respond_to?(:package_name)
return include_package(package_name, &b)
include_package(package_name, &block)
end

def java_alias(new_id, old_id)
@java_aliases[new_id] = old_id
(@java_aliases ||= {})[new_id] = old_id
end

end
2 changes: 1 addition & 1 deletion lib/pom.rb
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ def version

default_gems =
[
ImportedGem.new( 'jruby-openssl', '0.9.8', true ),
ImportedGem.new( 'jruby-openssl', '0.9.10', true ),
ImportedGem.new( 'jruby-readline', '1.0', false ),
ImportedGem.new( 'rake', 'rake.version', true ),
ImportedGem.new( 'rdoc', 'rdoc.version', true ),
Loading

0 comments on commit 606ff69

Please sign in to comment.