Skip to content

Commit

Permalink
Merge branch 'master' into JRUBY-6785
Browse files Browse the repository at this point in the history
  • Loading branch information
donv committed Jul 25, 2012
2 parents 3118cd9 + 846be19 commit bce5609
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 34 deletions.
7 changes: 4 additions & 3 deletions src/jruby/kernel19/proc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ def curry(curried_arity = nil)

m = lambda? ? :lambda : :proc
f = send(m) {|*x|
args += x
if args.length >= arity
self[*args]
call_args = args + x
if call_args.length >= arity
self[*call_args]
else
args = call_args
f
end
}
Expand Down
2 changes: 1 addition & 1 deletion src/org/jruby/BasicObjectStub.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public static RubyClass getType(IRubyObject self) {
}

public static boolean respondsTo(IRubyObject self, String name) {
if(getMetaClass(self).searchMethod("respond_to?") == getRuntime(self).getRespondToMethod()) {
if(getMetaClass(self).searchMethod("respond_to?").equals(getRuntime(self).getRespondToMethod())) {
return getMetaClass(self).isMethodBound(name, false);
} else {
return callMethod(self, getRuntime(self).getCurrentContext(), "respond_to?", getRuntime(self).newSymbol(name)).isTrue();
Expand Down
42 changes: 31 additions & 11 deletions src/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,13 @@ private void init() {
initRubyKernel();

if(config.isProfiling()) {
// additional twiddling for profiled mode
getLoadService().require("jruby/profiler/shutdown_hook");

// recache core methods, since they'll have profiling wrappers now
kernelModule.invalidateCacheDescendants(); // to avoid already-cached methods
RubyKernel.recacheBuiltinMethods(this);
RubyBasicObject.recacheBuiltinMethods(this);
}

if (config.getLoadGemfile()) {
Expand Down Expand Up @@ -1646,14 +1652,6 @@ private void addBuiltinIfAllowed(String name, Library lib) {
loadService.addBuiltinLibrary(name,lib);
}
}

public Object getRespondToMethod() {
return respondToMethod;
}

public void setRespondToMethod(Object rtm) {
this.respondToMethod = rtm;
}

public IRManager getIRManager() {
return irManager;
Expand Down Expand Up @@ -1729,42 +1727,66 @@ void setKernel(RubyModule kernelModule) {
this.kernelModule = kernelModule;
}

///////////////////////////////////////////////////////////////////////////
// Cached DynamicMethod objects, used for direct dispatch or for short
// circuiting dynamic invocation logic.
///////////////////////////////////////////////////////////////////////////

public DynamicMethod getPrivateMethodMissing() {
return privateMethodMissing;
}

public void setPrivateMethodMissing(DynamicMethod method) {
privateMethodMissing = method;
}

public DynamicMethod getProtectedMethodMissing() {
return protectedMethodMissing;
}

public void setProtectedMethodMissing(DynamicMethod method) {
protectedMethodMissing = method;
}

public DynamicMethod getVariableMethodMissing() {
return variableMethodMissing;
}

public void setVariableMethodMissing(DynamicMethod method) {
variableMethodMissing = method;
}

public DynamicMethod getSuperMethodMissing() {
return superMethodMissing;
}

public void setSuperMethodMissing(DynamicMethod method) {
superMethodMissing = method;
}

public DynamicMethod getNormalMethodMissing() {
return normalMethodMissing;
}

public void setNormalMethodMissing(DynamicMethod method) {
normalMethodMissing = method;
}

public DynamicMethod getDefaultMethodMissing() {
return defaultMethodMissing;
}

public void setDefaultMethodMissing(DynamicMethod method) {
defaultMethodMissing = method;
}

public DynamicMethod getRespondToMethod() {
return respondTo;
}

public void setRespondToMethod(DynamicMethod rtm) {
this.respondTo = rtm;
}

public RubyClass getDummy() {
return dummyClass;
Expand Down Expand Up @@ -4307,7 +4329,7 @@ public void setFFI(FFI ffi) {
procSysModule, precisionModule, errnoModule;

private DynamicMethod privateMethodMissing, protectedMethodMissing, variableMethodMissing,
superMethodMissing, normalMethodMissing, defaultMethodMissing;
superMethodMissing, normalMethodMissing, defaultMethodMissing, respondTo;

// record separator var, to speed up io ops that use it
private GlobalVariable recordSeparatorVar;
Expand Down Expand Up @@ -4388,8 +4410,6 @@ public void setFFI(FFI ffi) {
// Weak map of all Modules in the system (and by extension, all Classes
private final Set<RubyModule> allModules = new WeakHashSet<RubyModule>();

private Object respondToMethod;

private final Map<String, DateTimeZone> timeZoneCache = new HashMap<String,DateTimeZone>();
/**
* A list of "external" finalizers (the ones, registered via ObjectSpace),
Expand Down
10 changes: 7 additions & 3 deletions src/org/jruby/RubyArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -1858,9 +1858,13 @@ public IRubyObject join19(final ThreadContext context, IRubyObject sep) {
if (realLength == 0) return RubyString.newEmptyString(runtime, USASCIIEncoding.INSTANCE);

if (sep.isNil()) sep = runtime.getGlobalVariables().get("$,");

RubyString sepString = sep.convertToString();
int len = 1 + sepString.size() * (realLength - 1);

int len = 1;
RubyString sepString = null;
if (!sep.isNil()) {
sepString = sep.convertToString();
len += sepString.size() * (realLength - 1);
}

for (int i = begin; i < begin + realLength; i++) {
IRubyObject val = safeArrayRef(values, i);
Expand Down
12 changes: 10 additions & 2 deletions src/org/jruby/RubyBasicObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,19 @@ public static RubyClass createBasicObjectClass(Ruby runtime, RubyClass objectCla

objectClass.defineAnnotatedMethods(RubyBasicObject.class);

runtime.setDefaultMethodMissing(objectClass.searchMethod("method_missing"));
recacheBuiltinMethods(runtime);

return objectClass;
}

static void recacheBuiltinMethods(Ruby runtime) {
RubyModule objectClass = runtime.getBasicObject();

if (runtime.is1_9()) { // method_missing is in Kernel in 1.9
runtime.setDefaultMethodMissing(objectClass.searchMethod("method_missing"));
}
}

@JRubyMethod(name = "initialize", visibility = PRIVATE, compat = RUBY1_9)
public IRubyObject initialize19(ThreadContext context) {
return context.nil;
Expand Down Expand Up @@ -578,7 +586,7 @@ public RubyClass getType() {
*/
public final boolean respondsTo(String name) {
DynamicMethod method = getMetaClass().searchMethod("respond_to?");
if(method == getRuntime().getRespondToMethod()) {
if(method.equals(getRuntime().getRespondToMethod())) {
// fastest path; builtin respond_to? which just does isMethodBound
return getMetaClass().isMethodBound(name, false);
} else if (!method.isUndefined()) {
Expand Down
9 changes: 5 additions & 4 deletions src/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import org.jruby.compiler.impl.SkinnyMethodAdapter;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.ProfilingDynamicMethod;
import org.jruby.java.codegen.RealClassGenerator;
import org.jruby.java.codegen.Reified;
import org.jruby.javasupport.Java;
Expand Down Expand Up @@ -685,7 +686,7 @@ public IRubyObject finvokeChecked(ThreadContext context, IRubyObject self, Strin
DynamicMethod method = searchMethod(name);
if(method.isUndefined()) {
DynamicMethod methodMissing = searchMethod("method_missing");
if(methodMissing.isUndefined() || methodMissing == context.getRuntime().getDefaultMethodMissing()) {
if(methodMissing.isUndefined() || methodMissing.equals(context.getRuntime().getDefaultMethodMissing())) {
return null;
}

Expand Down Expand Up @@ -1732,7 +1733,7 @@ public void smartDump(MarshalStream stream, IRubyObject target) throws IOExcepti
} else {
// recache
DynamicMethod method = searchMethod("respond_to?");
if (method != runtime.getRespondToMethod() && !method.isUndefined()) {
if (!method.equals(runtime.getRespondToMethod()) && !method.isUndefined()) {

// custom respond_to?, always do slow default marshaling
tuple = (cachedDumpMarshal = new MarshalTuple(null, MarshalType.DEFAULT_SLOW, generation));
Expand Down Expand Up @@ -1783,7 +1784,7 @@ public IRubyObject smartLoadNewUser(IRubyObject target, IRubyObject data) {
return target;
} else {
DynamicMethod method = searchMethod("respond_to?");
if (method != runtime.getRespondToMethod() && !method.isUndefined()) {
if (!method.equals(runtime.getRespondToMethod()) && !method.isUndefined()) {

// custom respond_to?, cache nothing and use slow path
if (method.call(context, target, this, "respond_to?", runtime.newSymbol("marshal_load")).isTrue()) {
Expand Down Expand Up @@ -1834,7 +1835,7 @@ public IRubyObject smartLoadOldUser(IRubyObject data) {
return cache.method.call(context, this, getSingletonClass(), "_load", data);
} else {
DynamicMethod method = getSingletonClass().searchMethod("respond_to?");
if (method != runtime.getRespondToMethod() && !method.isUndefined()) {
if (!method.equals(runtime.getRespondToMethod()) && !method.isUndefined()) {

// custom respond_to?, cache nothing and use slow path
if (method.call(context, this, getSingletonClass(), "respond_to?", runtime.newSymbol("_load")).isTrue()) {
Expand Down
3 changes: 2 additions & 1 deletion src/org/jruby/RubyFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,8 @@ private Stream fopen(String path, ModeFlags flags) {
} catch (FileNotFoundException ex) {
// FNFException can be thrown in both cases, when the file
// is not found, or when permission is denied.
if (Ruby.isSecurityRestricted() || new File(getRuntime().getCurrentDirectory(), path).exists()) {
// FIXME: yes, this is indeed gross.
if (ex.getMessage().contains(/*P*/"ermission denied")) {
throw getRuntime().newErrnoEACCESError(path);
}
throw getRuntime().newErrnoENOENTError(path);
Expand Down
20 changes: 16 additions & 4 deletions src/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ public static RubyModule createKernelModule(Ruby runtime) {

module.defineAnnotatedMethods(RubyKernel.class);

runtime.setRespondToMethod(module.searchMethod("respond_to?"));

module.setFlag(RubyObject.USER7_F, false); //Kernel is the only Module that doesn't need an implementor

runtime.setPrivateMethodMissing(new MethodMissingMethod(module) {
Expand Down Expand Up @@ -146,11 +144,25 @@ public IRubyObject methodMissing(ThreadContext context, IRubyObject self, RubyMo
}
});

recacheBuiltinMethods(runtime);

return module;
}

/**
* Cache built-in versions of several core methods, to improve performance by using identity comparison (==) rather
* than going ahead with dynamic dispatch.
*
* @param runtime
*/
static void recacheBuiltinMethods(Ruby runtime) {
RubyModule module = runtime.getKernel();

runtime.setRespondToMethod(module.searchMethod("respond_to?"));

if (!runtime.is1_9()) { // method_missing is in BasicObject in 1.9
runtime.setDefaultMethodMissing(module.searchMethod("method_missing"));
}

return module;
}

@JRubyMethod(module = true, visibility = PRIVATE)
Expand Down
25 changes: 25 additions & 0 deletions src/org/jruby/ext/ffi/jffi/JITNativeInvoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,22 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klaz
throw context.getRuntime().newArgumentError(3, arity);
}

public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4) {
throw context.getRuntime().newArgumentError(4, arity);
}

public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4, IRubyObject arg5) {
throw context.getRuntime().newArgumentError(5, arity);
}

public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4,
IRubyObject arg5, IRubyObject arg6) {
throw context.getRuntime().newArgumentError(6, arity);
}

@Override
public final IRubyObject call(ThreadContext context, IRubyObject self,
RubyModule clazz, String name, IRubyObject[] args) {
Expand All @@ -155,6 +171,15 @@ public final IRubyObject call(ThreadContext context, IRubyObject self,
case 3:
return call(context, self, clazz, name, args[0], args[1], args[2]);

case 4:
return call(context, self, clazz, name, args[0], args[1], args[2], args[3]);

case 5:
return call(context, self, clazz, name, args[0], args[1], args[2], args[3], args[4]);

case 6:
return call(context, self, clazz, name, args[0], args[1], args[2], args[3], args[4], args[5]);

default:
throw context.getRuntime().newArgumentError("too many arguments: " + args.length);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,17 @@ public CallConfiguration getCallConfig() {
public Arity getArity() {
return delegate.getArity();
}

@Override
/**
* We override equals so that for method identity checks we treat delegating wrappers the same as the original
* methods. See e.g. RubyClass.finvokeChecked and its method_missing comparison.
*/
public boolean equals(Object other) {
if (other instanceof DelegatingDynamicMethod) {
return delegate.equals(((DelegatingDynamicMethod)other).getDelegate());
}

return delegate.equals(other);
}
}
6 changes: 3 additions & 3 deletions src/org/jruby/javasupport/util/RuntimeHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ public static DynamicMethod selectMethodMissing(ThreadContext context, IRubyObje
}

DynamicMethod methodMissing = receiver.getMetaClass().searchMethod("method_missing");
if (methodMissing.isUndefined() || methodMissing == runtime.getDefaultMethodMissing()) {
if (methodMissing.isUndefined() || methodMissing.equals(runtime.getDefaultMethodMissing())) {
return selectInternalMM(runtime, visibility, callType);
}
return new MethodMissingMethod(methodMissing, callType);
Expand All @@ -458,7 +458,7 @@ public static DynamicMethod selectMethodMissing(ThreadContext context, RubyClass
}

DynamicMethod methodMissing = selfClass.searchMethod("method_missing");
if (methodMissing.isUndefined() || methodMissing == runtime.getDefaultMethodMissing()) {
if (methodMissing.isUndefined() || methodMissing.equals(runtime.getDefaultMethodMissing())) {
return selectInternalMM(runtime, visibility, callType);
}
return new MethodMissingMethod(methodMissing, callType);
Expand All @@ -472,7 +472,7 @@ public static DynamicMethod selectMethodMissing(RubyClass selfClass, Visibility
}

DynamicMethod methodMissing = selfClass.searchMethod("method_missing");
if (methodMissing.isUndefined() || methodMissing == runtime.getDefaultMethodMissing()) {
if (methodMissing.isUndefined() || methodMissing.equals(runtime.getDefaultMethodMissing())) {
return selectInternalMM(runtime, visibility, callType);
}
return new MethodMissingMethod(methodMissing, callType);
Expand Down
4 changes: 2 additions & 2 deletions src/org/jruby/runtime/callsite/RespondToCallSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected IRubyObject cacheAndCall(IRubyObject caller, RubyClass selfType, Threa
// alternate logic to cache the result of respond_to if it's the standard one
// FIXME: 1.9's respond_to_missing breaks this, so we have to bail out
if (!context.runtime.is1_9() &&
entry.method == context.getRuntime().getRespondToMethod()) {
entry.method.equals(context.getRuntime().getRespondToMethod())) {
String name = arg.asJavaString();
RespondToTuple tuple = recacheRespondsTo(entry, name, selfType, true, context);
respondToTuple = tuple;
Expand All @@ -95,7 +95,7 @@ protected IRubyObject cacheAndCall(IRubyObject caller, RubyClass selfType, Threa
// FIXME: 1.9's respond_to_missing breaks this, so we have to bail out
// FIXME: 1.9's respond_to_missing breaks this, so we have to bail out
if (!context.runtime.is1_9() &&
entry.method == context.runtime.getRespondToMethod()) {
entry.method.equals(context.runtime.getRespondToMethod())) {
String name = arg0.asJavaString();
RespondToTuple tuple = recacheRespondsTo(entry, name, selfType, !arg1.isTrue(), context);
respondToTuple = tuple;
Expand Down

0 comments on commit bce5609

Please sign in to comment.