From 8efc2debb0958e6054b286dde1d0a9549b148884 Mon Sep 17 00:00:00 2001 From: "Thomas E. Enebo" Date: Thu, 25 Feb 2021 09:00:19 -0600 Subject: [PATCH 1/5] PROC block types in helpers only call prepareProcArgs. Check removed with assumption that only PROC will use it. --- core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java b/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java index 984b37c74d4..b6c9328b357 100644 --- a/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java +++ b/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java @@ -1928,11 +1928,12 @@ public static IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) { return args; } + // This is always for PROC type private static IRubyObject[] prepareProcArgs(ThreadContext context, Block b, IRubyObject[] args) { if (args.length != 1) return args; // Potentially expand single value if it is an array depending on what we are calling. - return IRRuntimeHelpers.convertValueIntoArgArray(context, args[0], b.getBody().getSignature(), args[0] instanceof RubyArray && b.type == Block.Type.NORMAL); + return IRRuntimeHelpers.convertValueIntoArgArray(context, args[0], b.getBody().getSignature(), false); } private static IRubyObject[] prepareBlockArgsInternal(ThreadContext context, Block block, IRubyObject[] args) { From 34ff7ce99381a206dedd06cecc9251f2bb7af5a7 Mon Sep 17 00:00:00 2001 From: "Thomas E. Enebo" Date: Thu, 25 Feb 2021 09:02:35 -0600 Subject: [PATCH 2/5] This pruning does not affect correctness --- core/src/main/java/org/jruby/runtime/BlockBody.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/java/org/jruby/runtime/BlockBody.java b/core/src/main/java/org/jruby/runtime/BlockBody.java index a0cdf34495a..ada582a351f 100644 --- a/core/src/main/java/org/jruby/runtime/BlockBody.java +++ b/core/src/main/java/org/jruby/runtime/BlockBody.java @@ -266,9 +266,6 @@ public IRubyObject[] prepareArgumentsForCall(ThreadContext context, IRubyObject[ if (args.length == 1) { // Convert value to arg-array, unwrapping where necessary args = IRRuntimeHelpers.convertValueIntoArgArray(context, args[0], signature, args[0] instanceof RubyArray && type == Block.Type.NORMAL); - } else if (signature.arityValue() == 1 && !signature.hasKwargs()) { - // discard excess arguments - args = args.length == 0 ? context.runtime.getSingleNilArray() : new IRubyObject[] { args[0] }; } } From 103503e7e8983d77b26210d850a2daa4c7a35d8e Mon Sep 17 00:00:00 2001 From: "Thomas E. Enebo" Date: Thu, 25 Feb 2021 12:53:14 -0600 Subject: [PATCH 3/5] Remove seemingly unused getSignature since they conflict with upcoming getSignature on NativeMethod --- .../main/java/org/jruby/ext/ffi/jffi/JITNativeInvoker.java | 4 ---- core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/core/src/main/java/org/jruby/ext/ffi/jffi/JITNativeInvoker.java b/core/src/main/java/org/jruby/ext/ffi/jffi/JITNativeInvoker.java index c4ef8fa626f..ba457b82abb 100644 --- a/core/src/main/java/org/jruby/ext/ffi/jffi/JITNativeInvoker.java +++ b/core/src/main/java/org/jruby/ext/ffi/jffi/JITNativeInvoker.java @@ -141,10 +141,6 @@ private static CachingCallSite getParameterCallSite(Signature signature, int par } } - Signature getSignature() { - return signature; - } - CallContext getCallContext() { return callContext; } diff --git a/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java b/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java index 33ff406e499..effd042e18b 100644 --- a/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java +++ b/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java @@ -56,10 +56,6 @@ public final boolean isNative() { return true; } - Signature getSignature() { - return signature; - } - CallContext getCallContext() { return function.getCallContext(); } From 87a692a7af40e6a581c037475b3688553984fe09 Mon Sep 17 00:00:00 2001 From: "Thomas E. Enebo" Date: Thu, 25 Feb 2021 12:59:31 -0600 Subject: [PATCH 4/5] Missed another getSignature plus removed now unused field --- core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethod.java | 4 ---- core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java | 2 -- 2 files changed, 6 deletions(-) diff --git a/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethod.java b/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethod.java index 500da9f2019..7a3a7097369 100644 --- a/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethod.java +++ b/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethod.java @@ -51,10 +51,6 @@ public DynamicMethod getMethodForCaching() { return compiledInvoker != null ? compiledInvoker : this; } - Signature getSignature() { - return signature; - } - CallContext getCallContext() { return function.getCallContext(); } diff --git a/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java b/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java index effd042e18b..a0d0c257734 100644 --- a/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java +++ b/core/src/main/java/org/jruby/ext/ffi/jffi/NativeInvoker.java @@ -19,14 +19,12 @@ abstract public class NativeInvoker extends DynamicMethod { protected final com.kenai.jffi.Function function; private final int cbIndex; private final NativeCallbackFactory cbFactory; - private final Signature signature; public NativeInvoker(RubyModule implementationClass, com.kenai.jffi.Function function, Signature signature) { super(implementationClass, Visibility.PUBLIC, "ffi"+function.getFunctionAddress()); this.arity = Arity.fixed(signature.getParameterCount()); this.function = function; - this.signature = signature; int cbIndex = -1; NativeCallbackFactory cbFactory = null; From 9ccc321a1180fabaad86307fae2c87600c898ff1 Mon Sep 17 00:00:00 2001 From: "Thomas E. Enebo" Date: Thu, 25 Feb 2021 16:32:24 -0600 Subject: [PATCH 5/5] Mortally wound Arity to elevate Signature to the throne. We have had a long-term goal to replace Arity with Signature (started in 2014?). The main issue is that Arity had no concept of keyword arguments. The math behind arity lives on via Ruby's arity method but the underlying structure needs more information. This commit completely deprecates all use of arity internally. There are a few removals of long deprecated code using Arity but we still have a lot of deprecated code just in case. For example, jruby-rack still depends on this on one constructor still which receives Arity. Anything which was using arity is now written in terms of Signature. The largest missing piece of DynamicMethod not having a getSignature. As mentioned in the last paragraph we only have a single live code path using Arity from jruby-rack. On the performance front we will do less work (although I doubt we will see much we can measure). In startings up Rails server on a single controller app we were doing 3k arity calcs and over 400k signature calcs. Now we are doing no arity calcs and only 2k signature calcs. With some better mechanism for Signature creation we could get this down to a few hundred. The second aspect of this is reducing memory about 1Mb for the same Rails app. Signature is about 100k now but since it is immutable we can reduce this down to close to 0 if we share all combos during creation. The more near term motivation was seeing a mixture of logic between arity and signature involved in block argument processing. This branch has already removed some complexity of block processing but every extra detail we need to keep in our head makes fixing block issues that much harder. --- .../java/org/jruby/AbstractRubyMethod.java | 13 +- .../main/java/org/jruby/RubyBasicObject.java | 19 +- core/src/main/java/org/jruby/RubyClass.java | 194 ++++++++---------- .../main/java/org/jruby/RubyEnumerable.java | 161 --------------- core/src/main/java/org/jruby/RubyIO.java | 2 +- core/src/main/java/org/jruby/RubyMethod.java | 13 +- .../java/org/jruby/anno/TypePopulator.java | 5 +- .../internal/runtime/AbstractIRMethod.java | 2 +- .../internal/runtime/methods/AliasMethod.java | 10 +- .../methods/DelegatingDynamicMethod.java | 8 +- .../runtime/methods/DynamicMethod.java | 30 +++ .../runtime/methods/HandleMethod.java | 7 +- .../internal/runtime/methods/JavaMethod.java | 62 ++++-- .../methods/PartialDelegatingMethod.java | 11 +- .../internal/runtime/methods/ProcMethod.java | 6 +- .../methods/ProfilingDynamicMethod.java | 3 +- .../passes/AddCallProtocolInstructions.java | 15 +- .../java/invokers/RubyToJavaInvoker.java | 11 +- .../jruby/java/proxies/ArrayJavaProxy.java | 6 +- .../org/jruby/javasupport/JavaPackage.java | 6 +- .../org/jruby/javasupport/ext/JavaLang.java | 5 +- .../proxy/JavaProxyConstructor.java | 2 +- .../java/org/jruby/runtime/CallBlock.java | 5 - .../java/org/jruby/runtime/CallBlock19.java | 10 - .../jruby/runtime/ContextAwareBlockBody.java | 5 - .../java/org/jruby/runtime/Signature.java | 89 ++++++-- 26 files changed, 300 insertions(+), 400 deletions(-) diff --git a/core/src/main/java/org/jruby/AbstractRubyMethod.java b/core/src/main/java/org/jruby/AbstractRubyMethod.java index 55c95f6fc09..61da27703ea 100644 --- a/core/src/main/java/org/jruby/AbstractRubyMethod.java +++ b/core/src/main/java/org/jruby/AbstractRubyMethod.java @@ -1,4 +1,5 @@ -/***** BEGIN LICENSE BLOCK ***** +/* + **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public @@ -35,7 +36,6 @@ import org.jruby.anno.JRubyMethod; import org.jruby.internal.runtime.methods.AliasMethod; import org.jruby.internal.runtime.methods.DynamicMethod; -import org.jruby.internal.runtime.methods.IRMethodArgs; import org.jruby.internal.runtime.methods.UndefinedMethod; import org.jruby.runtime.Helpers; import org.jruby.runtime.PositionAware; @@ -71,14 +71,7 @@ public DynamicMethod getMethod() { */ @JRubyMethod(name = "arity") public RubyFixnum arity() { - int value; - if (method instanceof IRMethodArgs) { - value = ((IRMethodArgs) method).getSignature().arityValue(); - } else { - value = method.getArity().getValue(); - } - - return getRuntime().newFixnum(value); + return getRuntime().newFixnum(method.getSignature().arityValue()); } @Deprecated diff --git a/core/src/main/java/org/jruby/RubyBasicObject.java b/core/src/main/java/org/jruby/RubyBasicObject.java index c8b15af5eed..2c80f583550 100644 --- a/core/src/main/java/org/jruby/RubyBasicObject.java +++ b/core/src/main/java/org/jruby/RubyBasicObject.java @@ -34,6 +34,7 @@ import org.jruby.parser.StaticScope; import org.jruby.runtime.JavaSites; import org.jruby.runtime.JavaSites.BasicObjectSites; +import org.jruby.runtime.Signature; import org.jruby.runtime.callsite.CacheEntry; import org.jruby.runtime.ivars.VariableAccessor; import java.io.IOException; @@ -602,23 +603,9 @@ public final boolean respondsTo(String name) { // respond_to? or respond_to_missing? is not defined, so we must dispatch to trigger method_missing if ( respondTo.isUndefined() ) { return sites(context).respond_to.call(context, this, this, mname).isTrue(); + } else { + return respondTo.callRespondTo(context, this, "respond_to?", entry.sourceModule, mname); } - - // respond_to? is defined, invoke already-retrieved method object - final String respondName = "respond_to?"; - - // We have to check and enforce arity - final Arity arity = respondTo.getArity(); - if ( arity.isFixed() ) { - if ( arity.required() == 1 ) { - return respondTo.call(context, this, entry.sourceModule, respondName, mname).isTrue(); - } - if ( arity.required() != 2 ) { - throw runtime.newArgumentError(str(runtime, ids(runtime, respondName), " must accept 1 or 2 arguments (requires " + arity.getValue() + ")")); - } - } - - return respondTo.call(context, this, entry.sourceModule, respondName, mname, runtime.getTrue()).isTrue(); } /** diff --git a/core/src/main/java/org/jruby/RubyClass.java b/core/src/main/java/org/jruby/RubyClass.java index 09e2cc423ac..ff4727647da 100644 --- a/core/src/main/java/org/jruby/RubyClass.java +++ b/core/src/main/java/org/jruby/RubyClass.java @@ -35,6 +35,7 @@ import org.jruby.parser.StaticScope; import org.jruby.runtime.Arity; import org.jruby.runtime.JavaSites; +import org.jruby.runtime.Signature; import org.jruby.runtime.callsite.CachingCallSite; import org.jruby.runtime.callsite.RespondToCallSite; import org.jruby.runtime.ivars.VariableAccessor; @@ -683,26 +684,14 @@ private static IRubyObject checkFuncallFailed(ThreadContext context, IRubyObject * MRI: check_funcall_respond_to */ private static boolean checkFuncallRespondTo(ThreadContext context, RubyClass klass, IRubyObject recv, String mid) { - final Ruby runtime = context.runtime; CacheEntry entry = klass.searchWithCache("respond_to?"); DynamicMethod me = entry.method; // NOTE: isBuiltin here would be NOEX_BASIC in MRI, a flag only added to respond_to?, method_missing, and // respond_to_missing? Same effect, I believe. - if (me != null && !me.isUndefined() && !me.isBuiltin()) { - int arityValue = me.getArity().getValue(); - - if (arityValue > 2) throw runtime.newArgumentError("respond_to? must accept 1 or 2 arguments (requires " + arityValue + ")"); + if (me == null || me.isUndefined() || me.isBuiltin()) return true; - IRubyObject result; - if (arityValue == 1) { - result = me.call(context, recv, entry.sourceModule, "respond_to?", runtime.newSymbol(mid)); - } else { - result = me.call(context, recv, entry.sourceModule, "respond_to?", runtime.newSymbol(mid), runtime.getTrue()); - } - return result.isTrue(); - } - return true; + return me.callRespondTo(context, recv, "respond_to?", entry.sourceModule, context.runtime.newSymbol(mid)); } /** @@ -716,20 +705,17 @@ private static boolean checkFuncallRespondTo(ThreadContext context, RubyClass kl // NOTE: isBuiltin here would be NOEX_BASIC in MRI, a flag only added to respond_to?, method_missing, and // respond_to_missing? Same effect, I believe. - if (!me.isUndefined() && !me.isBuiltin()) { - int arityValue = me.getArity().getValue(); + if (me.isUndefined() || me.isBuiltin()) return true; - if (arityValue > 2) throw runtime.newArgumentError("respond_to? must accept 1 or 2 arguments (requires " + arityValue + ")"); + int required = me.getSignature().required(); - boolean result; - if (arityValue == 1) { - result = respondToSite.respondsTo(context, recv, recv); - } else { - result = respondToSite.respondsTo(context, recv, recv, true); - } - return result; + if (required > 2) throw runtime.newArgumentError("respond_to? must accept 1 or 2 arguments (requires " + required + ")"); + + if (required == 1) { + return respondToSite.respondsTo(context, recv, recv); + } else { + return respondToSite.respondsTo(context, recv, recv, true); } - return true; } // MRI: check_funcall_callable @@ -750,14 +736,8 @@ private static IRubyObject checkFuncallMissing(ThreadContext context, RubyClass CacheEntry entry = klass.searchWithCache("respond_to_missing?"); DynamicMethod me = entry.method; // MRI: basic_obj_respond_to_missing ... - if (!me.isUndefined() && !me.isBuiltin()) { - IRubyObject ret; - if (me.getArity().getValue() == 1) { - ret = me.call(context, self, entry.sourceModule, "respond_to_missing?", runtime.newSymbol(method)); - } else { - ret = me.call(context, self, entry.sourceModule, "respond_to_missing?", runtime.newSymbol(method), runtime.getTrue()); - } - if ( ! ret.isTrue() ) return null; + if (!me.isUndefined() && !me.isBuiltin() && !me.callRespondTo(context, self, "respond_to_missing?", entry.sourceModule, runtime.newSymbol(method))) { + return null; } if ( klass.isMethodBuiltin("method_missing") ) return null; @@ -765,8 +745,7 @@ private static IRubyObject checkFuncallMissing(ThreadContext context, RubyClass final IRubyObject $ex = context.getErrorInfo(); try { return checkFuncallExec(context, self, method, args); - } - catch (RaiseException e) { + } catch (RaiseException e) { context.setErrorInfo($ex); // restore $! return checkFuncallFailed(context, self, method, runtime.getNoMethodError(), args); } @@ -779,14 +758,8 @@ private static IRubyObject checkFuncallMissing(ThreadContext context, RubyClass CacheEntry entry = respondToMissingSite.retrieveCache(klass); DynamicMethod me = entry.method; // MRI: basic_obj_respond_to_missing ... - if (!me.isUndefined() && !me.isBuiltin()) { - IRubyObject ret; - if (me.getArity().getValue() == 1) { - ret = me.call(context, self, entry.sourceModule, "respond_to_missing?", runtime.newSymbol(method)); - } else { - ret = me.call(context, self, entry.sourceModule, "respond_to_missing?", runtime.newSymbol(method), runtime.getTrue()); - } - if ( ! ret.isTrue() ) return null; + if (!me.isUndefined() && !me.isBuiltin() && !me.callRespondTo(context, self, "respond_to_missing?", entry.sourceModule, runtime.newSymbol(method))) { + return null; } if (methodMissingSite.retrieveCache(klass).method.isBuiltin()) return null; @@ -1536,30 +1509,28 @@ private void defineClassMethods(Set instanceMethods) { String signature; if (methodSignature == null) { - final Arity arity = methodEntry.getValue().getArity(); + Signature sig = methodEntry.getValue().getSignature(); // non-signature signature with just IRubyObject - switch (arity.getValue()) { - case 0: - signature = sig(IRubyObject.class); - if (instanceMethods.contains(javaMethodName + signature)) continue; - m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_STATIC, javaMethodName, signature, null, null); - generateMethodAnnotations(methodAnnos, m, parameterAnnos); - - m.getstatic(javaPath, "rubyClass", ci(RubyClass.class)); - //m.invokevirtual("org/jruby/RubyClass", "getMetaClass", sig(RubyClass.class) ); - m.ldc(id); - m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class) ); - break; - default: - signature = sig(IRubyObject.class, IRubyObject[].class); - if (instanceMethods.contains(javaMethodName + signature)) continue; - m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS | ACC_STATIC, javaMethodName, signature, null, null); - generateMethodAnnotations(methodAnnos, m, parameterAnnos); - - m.getstatic(javaPath, "rubyClass", ci(RubyClass.class)); - m.ldc(id); - m.aload(0); - m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class) ); + if (sig.isNoArguments()) { + signature = sig(IRubyObject.class); + if (instanceMethods.contains(javaMethodName + signature)) continue; + m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_STATIC, javaMethodName, signature, null, null); + generateMethodAnnotations(methodAnnos, m, parameterAnnos); + + m.getstatic(javaPath, "rubyClass", ci(RubyClass.class)); + //m.invokevirtual("org/jruby/RubyClass", "getMetaClass", sig(RubyClass.class) ); + m.ldc(id); + m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class)); + } else { + signature = sig(IRubyObject.class, IRubyObject[].class); + if (instanceMethods.contains(javaMethodName + signature)) continue; + m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS | ACC_STATIC, javaMethodName, signature, null, null); + generateMethodAnnotations(methodAnnos, m, parameterAnnos); + + m.getstatic(javaPath, "rubyClass", ci(RubyClass.class)); + m.ldc(id); + m.aload(0); + m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class) ); } m.areturn(); } @@ -1607,36 +1578,37 @@ private void defineInstanceMethods(Set instanceMethods) { final String signature; if (methodSignature == null) { // non-signature signature with just IRubyObject - final Arity arity = methodEntry.getValue().getArity(); - switch (arity.getValue()) { - case 0: - signature = sig(IRubyObject.class); // return IRubyObject foo() - m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null); - generateMethodAnnotations(methodAnnos, m, parameterAnnos); - - m.aload(0); - m.ldc(id); - m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class)); - break; - case 1: - signature = sig(IRubyObject.class, IRubyObject.class); // return IRubyObject foo(IRubyObject arg1) - m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null); - generateMethodAnnotations(methodAnnos, m, parameterAnnos); - - m.aload(0); - m.ldc(id); - m.aload(1); // IRubyObject arg1 - m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject.class)); - break; - // currently we only have : - // callMethod(context, name) - // callMethod(context, name, arg1) - // so for other arities use generic: - // callMethod(context, name, args...) - default: - if ( arity.isFixed() ) { - final int paramCount = arity.getValue(); - Class[] params = new Class[paramCount]; Arrays.fill(params, IRubyObject.class); + Signature sig = methodEntry.getValue().getSignature(); + if (sig.isFixed()) { + switch (sig.required()) { + case 0: + signature = sig(IRubyObject.class); // return IRubyObject foo() + m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null); + generateMethodAnnotations(methodAnnos, m, parameterAnnos); + + m.aload(0); + m.ldc(id); + m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class)); + break; + case 1: + signature = sig(IRubyObject.class, IRubyObject.class); // return IRubyObject foo(IRubyObject arg1) + m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null); + generateMethodAnnotations(methodAnnos, m, parameterAnnos); + + m.aload(0); + m.ldc(id); + m.aload(1); // IRubyObject arg1 + m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject.class)); + break; + default: + // currently we only have : + // callMethod(context, name) + // callMethod(context, name, arg1) + // so for other arities use generic: + // callMethod(context, name, args...) + final int paramCount = sig.required(); + Class[] params = new Class[paramCount]; + Arrays.fill(params, IRubyObject.class); signature = sig(IRubyObject.class, params); m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null); generateMethodAnnotations(methodAnnos, m, parameterAnnos); @@ -1647,28 +1619,28 @@ private void defineInstanceMethods(Set instanceMethods) { // generate an IRubyObject[] for the method arguments : m.pushInt(paramCount); m.anewarray(p(IRubyObject.class)); // new IRubyObject[size] - for ( int i = 1; i <= paramCount; i++ ) { + for (int i = 1; i <= paramCount; i++) { m.dup(); m.pushInt(i - 1); // array index e.g. iconst_0 m.aload(i); // IRubyObject arg1, arg2 e.g. aload_1 m.aastore(); // arr[ i - 1 ] = arg_i } - } - else { // (generic) variable arity e.g. method(*args) - // NOTE: maybe improve to match fixed part for < -1 e.g. (IRubObject, IRubyObject, IRubyObject...) - signature = sig(IRubyObject.class, IRubyObject[].class); - m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null); - generateMethodAnnotations(methodAnnos, m, parameterAnnos); - - m.aload(0); - m.ldc(id); - m.aload(1); // IRubyObject[] arg1 - } - m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class)); + m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class)); + } + } else { + // (generic) variable arity e.g. method(*args) + // NOTE: maybe improve to match fixed part for < -1 e.g. (IRubObject, IRubyObject, IRubyObject...) + signature = sig(IRubyObject.class, IRubyObject[].class); + m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null); + generateMethodAnnotations(methodAnnos, m, parameterAnnos); + + m.aload(0); + m.ldc(id); + m.aload(1); // IRubyObject[] arg1 + m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class)); } m.areturn(); - } - else { // generate a real method signature for the method, with to/from coercions + } else { // generate a real method signature for the method, with to/from coercions // indices for temp values Class[] params = new Class[methodSignature.length - 1]; diff --git a/core/src/main/java/org/jruby/RubyEnumerable.java b/core/src/main/java/org/jruby/RubyEnumerable.java index 17d48b40b69..3b281f322f0 100644 --- a/core/src/main/java/org/jruby/RubyEnumerable.java +++ b/core/src/main/java/org/jruby/RubyEnumerable.java @@ -2241,118 +2241,11 @@ public static IRubyObject none_p19(ThreadContext context, IRubyObject self, fina return none_p(context, self, null, block); } - @Deprecated - public static IRubyObject none_p(final ThreadContext context, IRubyObject self, final Block block, Arity callbackArity) { - try { - if (block.isGiven()) { - callEach(context.runtime, context, self, callbackArity, new BlockCallback() { - public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) { - checkContext(context, ctx, "none?"); - IRubyObject larg = packEnumValues(ctx, largs); - if (block.yield(ctx, larg).isTrue()) throw JumpException.SPECIAL_JUMP; - return ctx.nil; - } - @Override - public IRubyObject call(ThreadContext ctx, IRubyObject larg) { - checkContext(context, ctx, "none?"); - if (block.yield(ctx, larg).isTrue()) throw JumpException.SPECIAL_JUMP; - return ctx.nil; - } - }); - } else { - callEach(context, eachSite(context), self, Signature.ONE_REQUIRED, new BlockCallback() { - public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) { - checkContext(context, ctx, "none?"); - IRubyObject larg = packEnumValues(ctx, largs); - if (larg.isTrue()) throw JumpException.SPECIAL_JUMP; - return ctx.nil; - } - @Override - public IRubyObject call(ThreadContext ctx, IRubyObject larg) { - checkContext(context, ctx, "none?"); - if (larg.isTrue()) throw JumpException.SPECIAL_JUMP; - return ctx.nil; - } - }); - } - } catch (JumpException.SpecialJump sj) { - return context.fals; - } - return context.tru; - } - @Deprecated public static IRubyObject one_p19(ThreadContext context, IRubyObject self, final Block block) { return one_p(context, self, null, block); } - @Deprecated - public static IRubyObject one_p(final ThreadContext context, IRubyObject self, final Block block, Arity callbackArity) { - final Ruby runtime = context.runtime; - final boolean[] result = new boolean[] { false }; - - try { - if (block.isGiven()) { - callEach(runtime, context, self, callbackArity, new BlockCallback() { - public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) { - checkContext(context, ctx, "one?"); - IRubyObject larg = packEnumValues(ctx, largs); - if (block.yield(ctx, larg).isTrue()) { - if (result[0]) { - throw JumpException.SPECIAL_JUMP; - } else { - result[0] = true; - } - } - return ctx.nil; - } - @Override - public IRubyObject call(ThreadContext ctx, IRubyObject larg) { - checkContext(context, ctx, "one?"); - if (block.yield(ctx, larg).isTrue()) { - if (result[0]) { - throw JumpException.SPECIAL_JUMP; - } else { - result[0] = true; - } - } - return ctx.nil; - } - }); - } else { - callEach(context, eachSite(context), self, Signature.ONE_REQUIRED, new BlockCallback() { - public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) { - checkContext(context, ctx, "one?"); - IRubyObject larg = packEnumValues(ctx, largs); - if (larg.isTrue()) { - if (result[0]) { - throw JumpException.SPECIAL_JUMP; - } else { - result[0] = true; - } - } - return ctx.nil; - } - @Override - public IRubyObject call(ThreadContext ctx, IRubyObject larg) { - checkContext(context, ctx, "one?"); - if (larg.isTrue()) { - if (result[0]) { - throw JumpException.SPECIAL_JUMP; - } else { - result[0] = true; - } - } - return ctx.nil; - } - }); - } - } catch (JumpException.SpecialJump sj) { - return runtime.getFalse(); - } - return result[0] ? runtime.getTrue() : runtime.getFalse(); - } - protected static CachingCallSite eachSite(ThreadContext context) { return sites(context).each; } @@ -2379,19 +2272,6 @@ public static IRubyObject callEach(Ruby runtime, ThreadContext context, IRubyObj return Helpers.invoke(context, self, "each", args, CallBlock.newCallClosure(self, runtime.getEnumerable(), Signature.OPTIONAL, callback, context)); } - @Deprecated - public static IRubyObject callEach19(Ruby runtime, ThreadContext context, IRubyObject self, - Arity arity, BlockCallback callback) { - return Helpers.invoke(context, self, "each", CallBlock19.newCallClosure(self, runtime.getEnumerable(), - arity, callback, context)); - } - - @Deprecated - public static IRubyObject callEach(Ruby runtime, ThreadContext context, IRubyObject self, IRubyObject[] args, - Arity arity, BlockCallback callback) { - return Helpers.invoke(context, self, "each", args, CallBlock.newCallClosure(self, runtime.getEnumerable(), arity, callback, context)); - } - @Deprecated public static IRubyObject callEach(Ruby runtime, ThreadContext context, IRubyObject self, IRubyObject[] args, Signature signature, BlockCallback callback) { @@ -2399,13 +2279,6 @@ public static IRubyObject callEach(Ruby runtime, ThreadContext context, IRubyObj CallBlock.newCallClosure(context, self, signature, callback)); } - @Deprecated - public static IRubyObject callEach(Ruby runtime, ThreadContext context, IRubyObject self, - Arity arity, BlockCallback callback) { - return Helpers.invoke(context, self, "each", CallBlock.newCallClosure(self, runtime.getEnumerable(), - arity, callback, context)); - } - @Deprecated public static IRubyObject callEach19(Ruby runtime, ThreadContext context, IRubyObject self, Signature signature, BlockCallback callback) { @@ -2447,45 +2320,11 @@ public static IRubyObject find_index19(ThreadContext context, IRubyObject self, return find_index(context, self, block); } - @Deprecated - public static IRubyObject find_index(ThreadContext context, IRubyObject self, final Block block, Arity callbackArity) { - boolean blockGiven = block.isGiven(); - - if (self instanceof RubyArray && blockGiven) return ((RubyArray) self).find_index(context, block); - - return blockGiven ? find_indexCommon(context, self, block, callbackArity) : - enumeratorize(context.runtime, self, "find_index"); - } - @Deprecated public static IRubyObject find_index19(ThreadContext context, IRubyObject self, final IRubyObject cond, final Block block) { return find_index(context, self, cond, block); } - @Deprecated - public static IRubyObject find_indexCommon(ThreadContext context, IRubyObject self, final Block block, Arity callbackArity) { - final Ruby runtime = context.runtime; - final long result[] = new long[] {0}; - - try { - callEach(runtime, context, self, callbackArity, new BlockCallback() { - public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) { - return call(ctx, packEnumValues(ctx, largs), blk); - } - @Override - public IRubyObject call(ThreadContext ctx, IRubyObject larg, Block blk) { - if (block.yield(ctx, larg).isTrue()) throw JumpException.SPECIAL_JUMP; - result[0]++; - return ctx.nil; - } - }); - } catch (JumpException.SpecialJump sj) { - return RubyFixnum.newFixnum(runtime, result[0]); - } - - return context.nil; - } - @Deprecated public static IRubyObject collect19(ThreadContext context, IRubyObject self, final Block block) { return collect(context, self, block); diff --git a/core/src/main/java/org/jruby/RubyIO.java b/core/src/main/java/org/jruby/RubyIO.java index 811c3a366c4..97394383933 100644 --- a/core/src/main/java/org/jruby/RubyIO.java +++ b/core/src/main/java/org/jruby/RubyIO.java @@ -2626,7 +2626,7 @@ public static IRubyObject write(ThreadContext context, IRubyObject maybeIO, IRub CachingCallSite write = sites(context).write; // In MRI this is used for all multi-arg puts calls to write. Here, we just do it for two - if (write.retrieveCache(maybeIO.getMetaClass()).method.getArity() == Arity.ONE_ARGUMENT) { + if (write.retrieveCache(maybeIO.getMetaClass()).method.getSignature().isOneArgument()) { Ruby runtime = context.runtime; if (runtime.isVerbose() && maybeIO != runtime.getGlobalVariables().get("$stderr")) { warnWrite(runtime, maybeIO); diff --git a/core/src/main/java/org/jruby/RubyMethod.java b/core/src/main/java/org/jruby/RubyMethod.java index 6af405bd05b..7133e3067a3 100644 --- a/core/src/main/java/org/jruby/RubyMethod.java +++ b/core/src/main/java/org/jruby/RubyMethod.java @@ -137,14 +137,7 @@ public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) */ @JRubyMethod public RubyFixnum arity() { - int value; - if (method instanceof IRMethodArgs) { - value = ((IRMethodArgs) method).getSignature().arityValue(); - } else { - value = method.getArity().getValue(); - } - - return getRuntime().newFixnum(value); + return getRuntime().newFixnum(method.getSignature().arityValue()); } @JRubyMethod(name = "eql?", required = 1) @@ -220,13 +213,11 @@ public IRubyObject to_proc(ThreadContext context) { Ruby runtime = context.runtime; MethodBlockBody body; - Signature signature; + Signature signature = method.getSignature(); ArgumentDescriptor[] argsDesc; if (method instanceof IRMethodArgs) { - signature = ((IRMethodArgs) method).getSignature(); argsDesc = ((IRMethodArgs) method).getArgumentDescriptors(); } else { - signature = Signature.from(method.getArity()); argsDesc = Helpers.methodToArgumentDescriptors(method); } diff --git a/core/src/main/java/org/jruby/anno/TypePopulator.java b/core/src/main/java/org/jruby/anno/TypePopulator.java index 3236bc6d701..a893032f787 100644 --- a/core/src/main/java/org/jruby/anno/TypePopulator.java +++ b/core/src/main/java/org/jruby/anno/TypePopulator.java @@ -40,6 +40,7 @@ import org.jruby.runtime.Block; import org.jruby.runtime.MethodFactory; import org.jruby.runtime.MethodIndex; +import org.jruby.runtime.Signature; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; @@ -48,7 +49,7 @@ public abstract class TypePopulator { public static void populateMethod(JavaMethod javaMethod, int arity, String simpleName, boolean isStatic, boolean notImplemented) { javaMethod.setIsBuiltin(true); - javaMethod.setArity(Arity.createArity(arity)); + javaMethod.setSignature(Signature.fromArityValue(arity)); javaMethod.setJavaName(simpleName); javaMethod.setSingleton(isStatic); javaMethod.setNotImplemented(notImplemented); @@ -57,7 +58,7 @@ public static void populateMethod(JavaMethod javaMethod, int arity, String simpl public static void populateMethod(JavaMethod javaMethod, int arity, String simpleName, boolean isStatic, boolean notImplemented, Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeArguments) { javaMethod.setIsBuiltin(true); - javaMethod.setArity(Arity.createArity(arity)); + javaMethod.setSignature(Signature.fromArityValue(arity)); javaMethod.setJavaName(simpleName); javaMethod.setSingleton(isStatic); javaMethod.setNotImplemented(notImplemented); diff --git a/core/src/main/java/org/jruby/internal/runtime/AbstractIRMethod.java b/core/src/main/java/org/jruby/internal/runtime/AbstractIRMethod.java index 67f1bf35853..d16197cc4ab 100644 --- a/core/src/main/java/org/jruby/internal/runtime/AbstractIRMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/AbstractIRMethod.java @@ -119,7 +119,7 @@ public Signature getSignature() { return signature; } - @Override + @Deprecated @Override public Arity getArity() { return signature.arity(); } diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/AliasMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/AliasMethod.java index 549ac71652c..c59532a48ad 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/AliasMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/AliasMethod.java @@ -37,6 +37,7 @@ import org.jruby.runtime.Arity; import org.jruby.runtime.Block; import org.jruby.runtime.Helpers; +import org.jruby.runtime.Signature; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.callsite.CacheEntry; @@ -128,11 +129,18 @@ public DynamicMethod dup() { return new AliasMethod(implementationClass, entry, name); } - @Override + + @Deprecated @Override public Arity getArity(){ return entry.method.getArity(); } + @Override + public Signature getSignature() { + return entry.method.getSignature(); + } + + public String getOldName() { return entry.method.getName(); } diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/DelegatingDynamicMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/DelegatingDynamicMethod.java index da125f58d33..48271af4caf 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/DelegatingDynamicMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/DelegatingDynamicMethod.java @@ -33,6 +33,7 @@ import org.jruby.runtime.Arity; import org.jruby.runtime.Block; import org.jruby.runtime.CallType; +import org.jruby.runtime.Signature; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; @@ -161,11 +162,16 @@ public boolean isImplementedBy(RubyModule other) { return delegate.isImplementedBy(other); } - @Override + @Deprecated @Override public Arity getArity() { return delegate.getArity(); } + @Override + public Signature getSignature() { + return delegate.getSignature(); + } + @Override public String getName() { return delegate.getName(); //To change body of overridden methods use File | Settings | File Templates. diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/DynamicMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/DynamicMethod.java index a1cc54b3983..f5025aed4f2 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/DynamicMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/DynamicMethod.java @@ -38,10 +38,13 @@ import org.jruby.MetaClass; import org.jruby.PrependedModule; +import org.jruby.Ruby; import org.jruby.RubyModule; +import org.jruby.RubySymbol; import org.jruby.runtime.Arity; import org.jruby.runtime.Block; import org.jruby.runtime.CallType; +import org.jruby.runtime.Signature; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; @@ -223,7 +226,24 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klaz return call(context, self, klazz, name, new IRubyObject[] {arg0, arg1, arg2}, block); } + /** + * Will call respond_to?/respond_to_missing? on object and name + */ + public boolean callRespondTo(ThreadContext context, IRubyObject self, String respondToMethodName, RubyModule klazz, RubySymbol name) { + Signature signature = getSignature(); + if (signature.isFixed()) { + int required = signature.required(); + + if (required == 1) { + return call(context, self, klazz, respondToMethodName, name).isTrue(); + } else if (required != 2) { + throw context.runtime.newArgumentError(respondToMethodName + " " + "must accept 1 or 2 arguments (requires " + required + ")"); + } + } + + return call(context, self, klazz, respondToMethodName, name, context.runtime.getTrue()).isTrue(); + } /** * Duplicate this method, returning DynamicMethod referencing the same code @@ -389,10 +409,20 @@ public final boolean isNull() { * * @return The arity of the method, as reported to Ruby consumers. */ + @Deprecated public Arity getArity() { return Arity.optional(); } + /** + * Retrieve the signature of this method. + * + * @return the signature + */ + public Signature getSignature() { + return Signature.OPTIONAL; + } + /** * Get the "real" method contained within this method. This simply returns * self except in cases where a method is wrapped to give it a new diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/HandleMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/HandleMethod.java index e6f2b7fefac..bc82aacbce2 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/HandleMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/HandleMethod.java @@ -104,11 +104,16 @@ public HandleMethod( this.maker4 = maker4; } - @Override + @Deprecated @Override public Arity getArity() { return signature.arity(); } + @Override + public Signature getSignature() { + return signature; + } + @Override public boolean isBuiltin() { return builtin; diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/JavaMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/JavaMethod.java index 1bba98a279a..293f997b4fb 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/JavaMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/JavaMethod.java @@ -1,4 +1,5 @@ -/***** BEGIN LICENSE BLOCK ***** +/* + **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public @@ -31,6 +32,7 @@ import org.jruby.runtime.Arity; import org.jruby.runtime.Block; import org.jruby.runtime.RubyEvent; +import org.jruby.runtime.Signature; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; @@ -41,7 +43,7 @@ /** */ public abstract class JavaMethod extends DynamicMethod implements Cloneable, MethodArgs2, NativeCallMethod { - protected Arity arity = Arity.OPTIONAL; + protected Signature signature = Signature.OPTIONAL; private String javaName; private boolean isSingleton; protected StaticScope staticScope; @@ -88,12 +90,6 @@ public JavaMethod(RubyModule implementationClass, Visibility visibility, String super(implementationClass, visibility, name); } - public void init(RubyModule implementationClass, Arity arity, Visibility visibility, StaticScope staticScope) { - this.staticScope = staticScope; - setArity(arity); - super.init(implementationClass, visibility); - } - public DynamicMethod dup() { try { return (JavaMethod) super.clone(); @@ -201,13 +197,22 @@ protected final void returnTraceCompiled(ThreadContext context, boolean enabled, if (enabled) context.trace(RubyEvent.RETURN, name, getImplementationClass()); } + @Deprecated public void setArity(Arity arity) { - this.arity = arity; + this.signature = Signature.from(arity); } - @Override + public void setSignature(Signature signature) { + this.signature = signature; + } + + @Deprecated @Override public Arity getArity() { - return arity; + return getSignature().arity(); + } + + public Signature getSignature() { + return signature; } public void setJavaName(String javaName) { @@ -656,10 +661,14 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz return call(context, self, clazz, name, args[0], block); } - @Override + @Deprecated @Override public Arity getArity() { return Arity.ONE_ARGUMENT; } + + public Signature getSignature() { + return Signature.ONE_ARGUMENT; + } } public static abstract class JavaMethodOneOrTwoBlock extends JavaMethodOneOrTwoOrNBlock { @@ -1099,10 +1108,14 @@ public final IRubyObject call(ThreadContext context, IRubyObject self, RubyModul if (args.length != 0) return raiseArgumentError(this, context, name, args.length, 0, 0); return call(context, self, clazz, name); } - @Override + @Deprecated @Override public Arity getArity() { return Arity.NO_ARGUMENTS; } + + public Signature getSignature() { + return Signature.NO_ARGUMENTS; + } } public static abstract class JavaMethodZeroOrOne extends JavaMethodZeroOrOneOrN { @@ -1216,10 +1229,14 @@ public final IRubyObject call(ThreadContext context, IRubyObject self, RubyModul return call(context, self, clazz, name, args[0]); } - @Override + @Deprecated @Override public Arity getArity() { return Arity.ONE_ARGUMENT; } + + public Signature getSignature() { + return Signature.ONE_ARGUMENT; + } } public static abstract class JavaMethodOneOrTwo extends JavaMethodOneOrTwoOrN { @@ -1297,10 +1314,14 @@ public final IRubyObject call(ThreadContext context, IRubyObject self, RubyModul return call(context, self, clazz, name, args[0], args[1]); } - @Override + @Deprecated @Override public Arity getArity() { return Arity.TWO_ARGUMENTS; } + + public Signature getSignature() { + return Signature.TWO_ARGUMENTS; + } } public static abstract class JavaMethodTwoOrThree extends JavaMethodTwoOrThreeOrN { @@ -1349,10 +1370,14 @@ public final IRubyObject call(ThreadContext context, IRubyObject self, RubyModul return call(context, self, clazz, name, args[0], args[1], args[2]); } - @Override + @Deprecated @Override public Arity getArity() { return Arity.THREE_ARGUMENTS; } + + public Signature getSignature() { + return Signature.THREE_ARGUMENTS; + } } @Deprecated @@ -1365,11 +1390,6 @@ public JavaMethod(RubyModule implementationClass, Visibility visibility, CallCon super(implementationClass, visibility, name); } - @Deprecated - public void init(RubyModule implementationClass, Arity arity, Visibility visibility, StaticScope staticScope, CallConfiguration callConfig) { - init(implementationClass, arity, visibility, staticScope); - } - @Deprecated public CallConfiguration getCallerRequirement() { return CallConfiguration.FrameNoneScopeNone; diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/PartialDelegatingMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/PartialDelegatingMethod.java index 092fa98326a..bba39f8ca3f 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/PartialDelegatingMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/PartialDelegatingMethod.java @@ -1,4 +1,5 @@ -/***** BEGIN LICENSE BLOCK ***** +/* + **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public @@ -32,6 +33,7 @@ import org.jruby.RubyModule; import org.jruby.runtime.Arity; import org.jruby.runtime.Block; +import org.jruby.runtime.Signature; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; @@ -116,11 +118,16 @@ public DynamicMethod getDelegate() { return method; } - @Override + @Deprecated @Override public Arity getArity() { return method.getArity(); } + @Override + public Signature getSignature() { + return method.getSignature(); + } + @Override public RubyModule getDefinedClass() { RubyModule definedClass = this.definedClass; diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/ProcMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/ProcMethod.java index bfc498e152d..db27fab0c43 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/ProcMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/ProcMethod.java @@ -74,10 +74,10 @@ public boolean isSame(DynamicMethod method) { return ((ProcMethod) method).proc == proc; } - - @Override + + @Deprecated @Override public Arity getArity() { - return proc.getBlock().getSignature().arity(); + return getSignature().arity(); } public String getFile() { diff --git a/core/src/main/java/org/jruby/internal/runtime/methods/ProfilingDynamicMethod.java b/core/src/main/java/org/jruby/internal/runtime/methods/ProfilingDynamicMethod.java index 667e80a0d52..1f27f07b64e 100644 --- a/core/src/main/java/org/jruby/internal/runtime/methods/ProfilingDynamicMethod.java +++ b/core/src/main/java/org/jruby/internal/runtime/methods/ProfilingDynamicMethod.java @@ -162,8 +162,7 @@ public DynamicMethod dup() { } public Signature getSignature() { - return delegate instanceof IRMethodArgs ? - ((IRMethodArgs) delegate).getSignature() : Signature.from(delegate.getArity()); + return delegate.getSignature(); } public ArgumentDescriptor[] getArgumentDescriptors() { diff --git a/core/src/main/java/org/jruby/ir/passes/AddCallProtocolInstructions.java b/core/src/main/java/org/jruby/ir/passes/AddCallProtocolInstructions.java index 0ee511e0d7b..88f7ce97c87 100644 --- a/core/src/main/java/org/jruby/ir/passes/AddCallProtocolInstructions.java +++ b/core/src/main/java/org/jruby/ir/passes/AddCallProtocolInstructions.java @@ -119,19 +119,12 @@ public Object execute(FullInterpreterContext fic, Object... data) { // Add the right kind of arg preparation instruction Signature sig = ((IRClosure)fic.getScope()).getSignature(); - int arityValue = sig.arityValue(); - if (arityValue == 0) { + if (sig.isNoArguments()) { prologueBB.addInstr(PrepareNoBlockArgsInstr.INSTANCE); + } else if (sig.isOneArgument()) { // no kwargs and just a single required argument + prologueBB.addInstr(PrepareSingleBlockArgInstr.INSTANCE); } else { - if (sig.isFixed()) { - if (arityValue == 1 && !sig.hasKwargs()) { - prologueBB.addInstr(PrepareSingleBlockArgInstr.INSTANCE); - } else { - prologueBB.addInstr(PrepareBlockArgsInstr.INSTANCE); - } - } else { - prologueBB.addInstr(PrepareBlockArgsInstr.INSTANCE); - } + prologueBB.addInstr(PrepareBlockArgsInstr.INSTANCE); } } else { if (needsFrame) { diff --git a/core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java b/core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java index 8fa14cccae0..07098ace873 100644 --- a/core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java +++ b/core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java @@ -48,6 +48,7 @@ import org.jruby.javasupport.JavaConstructor; import org.jruby.javasupport.ParameterTypes; import org.jruby.runtime.Arity; +import org.jruby.runtime.Signature; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.cli.Options; @@ -171,24 +172,24 @@ void initialize() { this.javaCallables = callables; this.javaVarargsCallables = varargsCallables; - setArity(minArity, maxArity, minVarArgsArity); + setSignature(minArity, maxArity, minVarArgsArity); setupNativeCall(); initialized = true; } } - private void setArity(final int minArity, final int maxArity, final int minVarArgsArity) { + private void setSignature(final int minArity, final int maxArity, final int minVarArgsArity) { if ( minVarArgsArity == -1 ) { // no var-args if ( minArity == maxArity ) { - setArity( Arity.fixed(minArity) ); + setSignature(Signature.from(minArity, 0, 0, 0, 0, Signature.Rest.NONE, -1)); } else { // multiple overloads - setArity(Arity.required(minArity)); // but <= maxArity + setSignature(Signature.from(minArity, maxArity - minArity, 0, 0, 0, Signature.Rest.NONE, -1)); } } else { - setArity( Arity.required(minVarArgsArity < minArity ? minVarArgsArity : minArity) ); + setSignature(Signature.from(minVarArgsArity < minArity ? minVarArgsArity : minArity, 0, 0, 0, 0, Signature.Rest.NORM, -1)); } } diff --git a/core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java b/core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java index 20b7872a8bf..d24eac539ba 100644 --- a/core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java +++ b/core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java @@ -464,15 +464,15 @@ public IRubyObject each_with_index(final ThreadContext context, final Block bloc return runtime.getEnumerator().callMethod("new", this, runtime.newSymbol("each_with_index")); } - final boolean arity2 = block.getSignature().arity() == Arity.TWO_ARGUMENTS; - + final boolean twoArguments = block.getSignature().isTwoArguments(); final Object array = getObject(); final int length = Array.getLength(array); for ( int i = 0; i < length; i++ ) { IRubyObject element = ArrayUtils.arefDirect(runtime, array, converter, i); final RubyInteger index = RubyFixnum.newFixnum(runtime, i); - if ( arity2 ) { + + if (twoArguments) { block.yieldSpecific(context, element, index); } else { block.yield(context, RubyArray.newArray(runtime, element, index)); diff --git a/core/src/main/java/org/jruby/javasupport/JavaPackage.java b/core/src/main/java/org/jruby/javasupport/JavaPackage.java index 10e535a46d8..98bc83302ea 100644 --- a/core/src/main/java/org/jruby/javasupport/JavaPackage.java +++ b/core/src/main/java/org/jruby/javasupport/JavaPackage.java @@ -374,10 +374,14 @@ public DynamicMethod dup() { } } - @Override + @Deprecated @Override public Arity getArity() { return Arity.NO_ARGUMENTS; } + public Signature getSignature() { + return Signature.NO_ARGUMENTS; + } } + private static String handlesMethod(final String name) { // FIXME: We should consider pure-bytelist search here. switch (name) { diff --git a/core/src/main/java/org/jruby/javasupport/ext/JavaLang.java b/core/src/main/java/org/jruby/javasupport/ext/JavaLang.java index d89fa49e850..42542295306 100644 --- a/core/src/main/java/org/jruby/javasupport/ext/JavaLang.java +++ b/core/src/main/java/org/jruby/javasupport/ext/JavaLang.java @@ -111,12 +111,13 @@ public static IRubyObject each_with_index(final ThreadContext context, final IRu } java.lang.Iterable iterable = unwrapIfJavaObject(self); java.util.Iterator iterator = iterable.iterator(); - final boolean arity2 = block.getSignature().arity() == Arity.TWO_ARGUMENTS; + final boolean twoArguments = block.getSignature().isTwoArguments(); int i = 0; while ( iterator.hasNext() ) { final RubyInteger index = RubyFixnum.newFixnum(runtime, i++); final Object value = iterator.next(); final IRubyObject rValue = convertJavaToUsableRubyObject(runtime, value); - if ( arity2 ) { + + if (twoArguments) { block.yieldSpecific(context, rValue, index); } else { block.yield(context, RubyArray.newArray(runtime, rValue, index)); diff --git a/core/src/main/java/org/jruby/javasupport/proxy/JavaProxyConstructor.java b/core/src/main/java/org/jruby/javasupport/proxy/JavaProxyConstructor.java index 986ede66692..ce47641171e 100644 --- a/core/src/main/java/org/jruby/javasupport/proxy/JavaProxyConstructor.java +++ b/core/src/main/java/org/jruby/javasupport/proxy/JavaProxyConstructor.java @@ -248,7 +248,7 @@ private IRubyObject invokeRuby(final DynamicMethod method, final JavaProxyMethod newArgs[i] = JavaUtil.convertJavaToUsableRubyObject(runtime, nargs[i]); } - final int arity = method.getArity().getValue(); + final int arity = method.getSignature().arityValue(); if ( arity < 0 || arity == newArgs.length ) { final ThreadContext context = runtime.getCurrentContext(); diff --git a/core/src/main/java/org/jruby/runtime/CallBlock.java b/core/src/main/java/org/jruby/runtime/CallBlock.java index 04fb5db6db3..e8f9465baee 100644 --- a/core/src/main/java/org/jruby/runtime/CallBlock.java +++ b/core/src/main/java/org/jruby/runtime/CallBlock.java @@ -52,11 +52,6 @@ public static Block newCallClosure(ThreadContext context, IRubyObject self, Sign return new Block(body, binding); } - @Deprecated - public static Block newCallClosure(IRubyObject self, RubyModule imClass, Arity arity, BlockCallback callback, ThreadContext context) { - return newCallClosure(self, imClass, Signature.from(arity), callback, context); - } - private CallBlock(ThreadContext context, Signature signature, BlockCallback callback) { super(signature); this.callback = callback; diff --git a/core/src/main/java/org/jruby/runtime/CallBlock19.java b/core/src/main/java/org/jruby/runtime/CallBlock19.java index d1bded8ec61..28943386129 100644 --- a/core/src/main/java/org/jruby/runtime/CallBlock19.java +++ b/core/src/main/java/org/jruby/runtime/CallBlock19.java @@ -47,16 +47,6 @@ public static Block newCallClosure(IRubyObject self, RubyModule imClass, Signatu return new Block(body, binding); } - // This is a stop-gap method where we try to construct an equivalent Signature from an Arity but beyond very simple Arity's it will strip - // some info off. - @Deprecated - public static Block newCallClosure(IRubyObject self, RubyModule imClass, Arity arity, BlockCallback callback, ThreadContext context) { - Binding binding = context.currentBinding(self, Visibility.PUBLIC); - BlockBody body = new CallBlock19(Signature.from(arity), callback, context); - - return new Block(body, binding); - } - public CallBlock19(Signature signature, BlockCallback callback, ThreadContext context) { super(signature); this.callback = callback; diff --git a/core/src/main/java/org/jruby/runtime/ContextAwareBlockBody.java b/core/src/main/java/org/jruby/runtime/ContextAwareBlockBody.java index 7cc0c4e518c..1e5a2117182 100644 --- a/core/src/main/java/org/jruby/runtime/ContextAwareBlockBody.java +++ b/core/src/main/java/org/jruby/runtime/ContextAwareBlockBody.java @@ -15,11 +15,6 @@ public ContextAwareBlockBody(StaticScope scope, Signature signature) { this.scope = scope; } - @Deprecated - public ContextAwareBlockBody(StaticScope scope, Arity arity, int argumentType) { - this(scope, Signature.from(arity)); - } - protected Frame pre(ThreadContext context, Block block) { return context.preYieldSpecificBlock(block.getBinding(), scope); } diff --git a/core/src/main/java/org/jruby/runtime/Signature.java b/core/src/main/java/org/jruby/runtime/Signature.java index b550767637f..5719b09bd66 100644 --- a/core/src/main/java/org/jruby/runtime/Signature.java +++ b/core/src/main/java/org/jruby/runtime/Signature.java @@ -37,10 +37,13 @@ public static Rest fromOrdinal(int ordinal) { public static final Signature ONE_ARGUMENT = new Signature(1, 0, 0, Rest.NONE, 0, 0, -1); public static final Signature TWO_ARGUMENTS = new Signature(2, 0, 0, Rest.NONE, 0, 0, -1); public static final Signature THREE_ARGUMENTS = new Signature(3, 0, 0, Rest.NONE, 0, 0, -1); + public static final Signature FOUR_ARGUMENTS = new Signature(4, 0, 0, Rest.NONE, 0, 0, -1); public static final Signature OPTIONAL = new Signature(0, 0, 0, Rest.NORM, 0, 0, -1); public static final Signature ONE_REQUIRED = new Signature(1, 0, 0, Rest.NORM, 0, 0, -1); public static final Signature TWO_REQUIRED = new Signature(2, 0, 0, Rest.NORM, 0, 0, -1); public static final Signature THREE_REQUIRED = new Signature(3, 0, 0, Rest.NORM, 0, 0, -1); + public static final Signature FOUR_REQUIRED = new Signature(4, 0, 0, Rest.NORM, 0, 0, -1); + public static final Signature ONE_OPT_ARGUMENT = new Signature(0, 1, 0, Rest.NONE, 0, 0, -1); private final short pre; private final short opt; @@ -48,7 +51,7 @@ public static Rest fromOrdinal(int ordinal) { private final short post; private final short kwargs; private final short requiredKwargs; - private final Arity arity; + private final int arityValue; private final int keyRest; public Signature(int pre, int opt, int post, Rest rest, int kwargs, int requiredKwargs, int keyRest) { @@ -59,16 +62,7 @@ public Signature(int pre, int opt, int post, Rest rest, int kwargs, int required this.kwargs = (short) kwargs; this.requiredKwargs = (short) requiredKwargs; this.keyRest = keyRest; - - // NOTE: Some logic to *assign* variables still uses Arity, which treats Rest.ANON (the - // |a,| form) as a rest arg for destructuring purposes. However ANON does *not* - // permit more than required args to be passed to a lambda, so we do not consider - // it a "true" rest arg for arity-checking purposes below in checkArity. - if (rest != Rest.NONE || opt != 0) { - arity = Arity.createArity(-(required() + 1)); - } else { - arity = Arity.fixed(required() + getRequiredKeywordForArityCount()); - } + this.arityValue = calculateArityValue(); } public int getRequiredKeywordForArityCount() { @@ -94,8 +88,42 @@ public boolean isFixed() { return arityValue() >= 0; } + /** + * Is this a signature with a no arguments of any kind? + */ + public boolean isNoArguments() { + return isFixed() && required() == 0; + } + + /** + * Is this a signature with a single fixed argument and NO keyword arguments? + */ + public boolean isOneArgument() { + return isFixed() && required() == 1; + } + + /** + * Is this a signature with a two fixed arguments and NO keyword arguments? + */ + public boolean isTwoArguments() { + return isFixed() && required() == 2; + } + public int required() { return pre + post; } - public Arity arity() { return arity; } + + // We calculate this every time but no one should be using this any more + @Deprecated + public Arity arity() { + // NOTE: Some logic to *assign* variables still uses Arity, which treats Rest.ANON (the + // |a,| form) as a rest arg for destructuring purposes. However ANON does *not* + // permit more than required args to be passed to a lambda, so we do not consider + // it a "true" rest arg for arity-checking purposes below in checkArity. + if (rest != Rest.NONE || opt != 0) { + return Arity.createArity(-(required() + 1)); + } else { + return Arity.fixed(required() + getRequiredKeywordForArityCount()); + } + } /** * Best attempt at breaking the code of arity values! We figure out how many fixed/required parameters @@ -103,7 +131,7 @@ public boolean isFixed() { * by multiplying -1 * (fixed + 1). Keyword args optional and rest values can indicate this optional * condition but only if no required keyword arguments are present. */ - public int arityValue() { + public int calculateArityValue() { int oneForKeywords = requiredKwargs > 0 ? 1 : 0; int fixedValue = pre() + post() + oneForKeywords; boolean hasOptionalKeywords = kwargs - requiredKwargs > 0; @@ -115,7 +143,32 @@ public int arityValue() { return fixedValue; } + public int arityValue() { + return arityValue; + } + + + // Lossy conversion to support populator constructors + public static Signature fromArityValue(int arityValue) { + boolean negative = arityValue < 0; + int value = negative ? -1 * arityValue - 1 : arityValue; + + switch(value) { + case 0: + return negative ? Signature.OPTIONAL : Signature.NO_ARGUMENTS; + case 1: + return negative ? Signature.ONE_REQUIRED : Signature.ONE_ARGUMENT; + case 2: + return negative ? Signature.TWO_REQUIRED : Signature.TWO_ARGUMENTS; + case 3: + return negative ? Signature.THREE_REQUIRED : Signature.THREE_ARGUMENTS; + } + + throw new UnsupportedOperationException("We do not know enough about the arity to convert it to a signature"); + } + // Lossy conversion to half-support older signatures which externally use Arity but needs to be converted. + @Deprecated public static Signature from(Arity arity) { switch(arity.required()) { case 0: @@ -166,7 +219,17 @@ public static Signature from(int pre, int opt, int post, int kwargs, int require return Signature.THREE_REQUIRED; } break; + case 4: + switch (rest) { + case NONE: + return Signature.FOUR_ARGUMENTS; + case NORM: + return Signature.FOUR_REQUIRED; + } + break; } + } else if (opt == 1 && pre == 0 && rest == Rest.NONE && post == 0 && kwargs == 0 && keyRest == -1) { + return Signature.ONE_OPT_ARGUMENT; } return new Signature(pre, opt, post, rest, kwargs, requiredKwargs, keyRest); }