Skip to content

Commit 95c5be4

Browse files
authored
Merge pull request #7732 from headius/more_indy_testing
Add more testing for invokedynamic modes
2 parents 9c5b3cc + 589bc92 commit 95c5be4

File tree

5 files changed

+124
-72
lines changed

5 files changed

+124
-72
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
target: ['test:mri:core:jit', 'spec:ruby:fast', 'spec:ruby:fast:jit', 'spec:ji', 'spec:ffi']
18+
target: ['test:jruby:int', 'spec:ruby:fast', 'spec:ji', 'spec:ffi']
1919
java-version: ['8', '17']
2020
fail-fast: false
2121

@@ -52,7 +52,7 @@ jobs:
5252

5353
strategy:
5454
matrix:
55-
target: ['test:mri:core:int', 'test:mri:extra', 'test:jruby:int', 'test:mri:stdlib', 'spec:ruby:slow', 'spec:ruby:debug', 'test:jruby:aot', 'test:slow_suites', 'spec:compiler', 'spec:regression', 'spec:jruby', 'spec:jrubyc', 'spec:profiler']
55+
target: ['test:mri:core:jit', 'test:mri:extra', 'spec:ruby:fast:jit', 'test:mri:stdlib', 'spec:ruby:slow', 'spec:ruby:debug', 'test:jruby:aot', 'test:slow_suites', 'spec:compiler', 'spec:regression', 'spec:jruby', 'spec:jrubyc', 'spec:profiler']
5656
fail-fast: false
5757

5858
name: rake ${{ matrix.target }} (Java 8)
@@ -118,12 +118,12 @@ jobs:
118118
- name: rake test:jruby
119119
run: bin/jruby --dev -S rake test:jruby
120120

121-
rake-test-indy:
121+
rake-test-17-indy:
122122
runs-on: ubuntu-latest
123123

124124
strategy:
125125
matrix:
126-
target: ['test:jruby:jit', 'spec:compiler', 'spec:ruby:fast:jit']
126+
target: ['test:mri:core:jit', 'test:jruby:jit', 'spec:compiler', 'spec:ruby:fast:jit']
127127
java-version: ['17']
128128
fail-fast: false
129129

@@ -165,7 +165,7 @@ jobs:
165165
matrix:
166166
package-flags: ['-Pmain', '-Pdist', '-Pcomplete', '-Posgi', '-Ptest', '-Pmain,test -Dinvoker.test=extended']
167167
# dist, complete, and osgi do not pass on 17 yet
168-
java-version: ['8', '11']
168+
java-version: ['11']
169169
fail-fast: false
170170

171171
name: mvn ${{ matrix.package-flags }} (Java ${{ matrix.java-version }})
@@ -233,7 +233,7 @@ jobs:
233233
env:
234234
PHASE: 'package ${{ matrix.package-flags }}'
235235

236-
ji-specs-indy:
236+
ji-specs-8-indy:
237237
runs-on: ubuntu-latest
238238

239239
strategy:
@@ -555,7 +555,7 @@ jobs:
555555
maven-test-openj9-8:
556556
runs-on: ubuntu-latest
557557

558-
name: mvn -Ptest (OpenJ9 Java 8)
558+
name: mvn -Ptest (OpenJ9 Java 8; disabled)
559559

560560
steps:
561561
- name: checkout
@@ -624,7 +624,7 @@ jobs:
624624
permissions:
625625
contents: none
626626
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/jruby-9.3' }}
627-
needs: [mvn-test, mvn-test-8, mvn-test-windows, dependency-check, rake-test, rake-test-indy, rake-test-8, test-versions, sequel, concurrent-ruby, jruby-tests-dev, ji-specs-indy, regression-specs-jit, mvn-test-m1]
627+
needs: [mvn-test, mvn-test-8, mvn-test-windows, dependency-check, rake-test, rake-test-17-indy, rake-test-8, test-versions, sequel, concurrent-ruby, jruby-tests-dev, ji-specs-8-indy, regression-specs-jit, mvn-test-m1]
628628
uses: jruby/jruby/.github/workflows/snapshot-publish.yml@6cd0d4d96d9406635183d81cf91acc82cd78245f
629629
secrets:
630630
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}

core/src/main/java/org/jruby/internal/runtime/methods/HandleMethod.java

Lines changed: 94 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
package org.jruby.internal.runtime.methods;
3030

3131
import java.lang.invoke.MethodHandle;
32-
import java.util.concurrent.Callable;
32+
import java.lang.invoke.MethodHandles;
33+
import java.util.function.Supplier;
3334

35+
import com.headius.invokebinder.SmartBinder;
3436
import org.jruby.RubyModule;
3537
import org.jruby.runtime.Arity;
3638
import org.jruby.runtime.Block;
@@ -40,6 +42,7 @@
4042
import org.jruby.runtime.Visibility;
4143
import org.jruby.runtime.builtin.IRubyObject;
4244

45+
import static org.jruby.runtime.Helpers.arrayOf;
4346
import static org.jruby.util.StringSupport.EMPTY_STRING_ARRAY;
4447
import static org.jruby.util.StringSupport.split;
4548

@@ -56,11 +59,11 @@
5659
* @author headius
5760
*/
5861
public class HandleMethod extends DynamicMethod implements MethodArgs2, Cloneable {
59-
private Callable<MethodHandle> maker0;
60-
private Callable<MethodHandle> maker1;
61-
private Callable<MethodHandle> maker2;
62-
private Callable<MethodHandle> maker3;
63-
private Callable<MethodHandle> maker4;
62+
private Supplier<MethodHandle> maker0;
63+
private Supplier<MethodHandle> maker1;
64+
private Supplier<MethodHandle> maker2;
65+
private Supplier<MethodHandle> maker3;
66+
private Supplier<MethodHandle> maker4;
6467
private MethodHandle target0;
6568
private MethodHandle target1;
6669
private MethodHandle target2;
@@ -74,6 +77,16 @@ public class HandleMethod extends DynamicMethod implements MethodArgs2, Cloneabl
7477
private final boolean builtin;
7578
private final boolean notImplemented;
7679

80+
private static final com.headius.invokebinder.Signature ARITY_0 =
81+
com.headius.invokebinder.Signature.from(
82+
IRubyObject.class,
83+
arrayOf(ThreadContext.class, IRubyObject.class, RubyModule.class, String.class, Block.class),
84+
"context", "self", "selfType", "name", "block");
85+
private static final com.headius.invokebinder.Signature ARITY_1 = ARITY_0.insertArg(4, "arg0", IRubyObject.class);
86+
private static final com.headius.invokebinder.Signature ARITY_2 = ARITY_1.insertArg(5, "arg1", IRubyObject.class);
87+
private static final com.headius.invokebinder.Signature ARITY_3 = ARITY_2.insertArg(6, "arg2", IRubyObject.class);
88+
private static final com.headius.invokebinder.Signature[] ARITIES = {ARITY_0, ARITY_1, ARITY_2, ARITY_3};
89+
7790
public HandleMethod(
7891
RubyModule implementationClass,
7992
Visibility visibility,
@@ -84,11 +97,11 @@ public HandleMethod(
8497
String parameterDesc,
8598
final int min,
8699
final int max,
87-
final Callable<MethodHandle> maker0,
88-
final Callable<MethodHandle> maker1,
89-
final Callable<MethodHandle> maker2,
90-
final Callable<MethodHandle> maker3,
91-
final Callable<MethodHandle> maker4) {
100+
final Supplier<MethodHandle> maker0,
101+
final Supplier<MethodHandle> maker1,
102+
final Supplier<MethodHandle> maker2,
103+
final Supplier<MethodHandle> maker3,
104+
final Supplier<MethodHandle> maker4) {
92105

93106
super(implementationClass, visibility, name);
94107
this.signature = Signature.decode(encodedSignature);
@@ -130,74 +143,118 @@ public boolean isNative() {
130143
}
131144

132145
private MethodHandle ensureTarget0() {
146+
MethodHandle target0;
133147
if (!initialized0) {
134-
this.target0 = safeCall(maker0);
148+
Supplier<MethodHandle> maker0 = this.maker0;
149+
if (maker0 == null) {
150+
target0 = adaptSpecificToVarargs(ensureTarget4(), 0);
151+
} else {
152+
target0 = maker0.get();
153+
}
154+
this.target0 = target0;
155+
this.maker0 = null;
135156
initialized0 = true;
136-
maker0 = null;
157+
} else {
158+
target0 = this.target0;
137159
}
138-
return this.target0;
160+
return target0;
139161
}
140162

141163
private MethodHandle ensureTarget1() {
164+
MethodHandle target1;
142165
if (!initialized1) {
143-
this.target1 = safeCall(maker1);
166+
Supplier<MethodHandle> maker1 = this.maker1;
167+
if (maker1 == null) {
168+
target1 = adaptSpecificToVarargs(ensureTarget4(), 1);
169+
} else {
170+
target1 = maker1.get();
171+
}
172+
this.target1 = target1;
173+
this.maker1 = null;
144174
initialized1 = true;
145-
maker1 = null;
175+
} else {
176+
target1 = this.target1;
146177
}
147-
return this.target1;
178+
return target1;
148179
}
149180

150181
private MethodHandle ensureTarget2() {
182+
MethodHandle target2;
151183
if (!initialized2) {
152-
this.target2 = safeCall(maker2);
184+
Supplier<MethodHandle> maker2 = this.maker2;
185+
if (maker2 == null) {
186+
target2 = adaptSpecificToVarargs(ensureTarget4(), 2);
187+
} else {
188+
target2 = maker2.get();
189+
}
190+
this.target2 = target2;
191+
this.maker2 = null;
153192
initialized2 = true;
154-
maker2 = null;
193+
} else {
194+
target2 = this.target2;
155195
}
156-
return this.target2;
196+
return target2;
157197
}
158198

159199
private MethodHandle ensureTarget3() {
200+
MethodHandle target3;
160201
if (!initialized3) {
161-
this.target3 = safeCall(maker3);
202+
Supplier<MethodHandle> maker3 = this.maker3;
203+
if (maker3 == null) {
204+
target3 = adaptSpecificToVarargs(ensureTarget4(), 3);
205+
} else {
206+
target3 = maker3.get();
207+
}
208+
this.target3 = target3;
209+
this.maker3 = null;
162210
initialized3 = true;
163-
maker3 = null;
211+
} else {
212+
target3 = this.target3;
164213
}
165-
return this.target3;
214+
return target3;
166215
}
167216

168217
private MethodHandle ensureTarget4() {
218+
MethodHandle target4;
169219
if (!initialized4) {
170-
this.target4 = safeCall(maker4);
220+
Supplier<MethodHandle> maker4 = this.maker4;
221+
if (maker4 == null) {
222+
target4 = null;
223+
} else {
224+
target4 = maker4.get();
225+
}
226+
this.target4 = target4;
171227
initialized4 = true;
172-
maker4 = null;
228+
this.maker4 = null;
173229
}
174230
return this.target4;
175231
}
176232

177-
private static MethodHandle safeCall(Callable<MethodHandle> maker) {
178-
try {
179-
if (maker == null) return null;
180-
return maker.call();
181-
} catch (Exception e) {
182-
Helpers.throwException(e);
183-
return null;
233+
private MethodHandle adaptSpecificToVarargs(MethodHandle varargs, int arity) {
234+
if (arity == 0) {
235+
return MethodHandles.insertArguments(varargs, 4, new Object[] {IRubyObject.NULL_ARRAY});
184236
}
237+
238+
return SmartBinder.from(ARITIES[arity])
239+
.permute("context", "self", "type", "name", "block", "arg.*")
240+
.collect("args", "arg.*")
241+
.permute("context", "self", "type", "name", "args", "block")
242+
.invoke(varargs).handle();
185243
}
186244

187245
@Override
188246
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
189247
try {
190248
MethodHandle target4 = ensureTarget4();
191249
if (target4 != null) {
192-
Arity.checkArgumentCount(context, args.length, min, max);
193250
return (IRubyObject) target4.invokeExact(context, self, clazz, name, args, block);
194251
} else {
195252
int arity = Arity.checkArgumentCount(context, args.length, min, max);
196253
switch (args.length) {
197-
case 0: return (IRubyObject) ensureTarget0().invokeExact(context, self, clazz, name, block);
198-
case 1: return (IRubyObject) ensureTarget1().invokeExact(context, self, clazz, name, args[0], block);
199-
case 2: return (IRubyObject) ensureTarget2().invokeExact(context, self, clazz, name, args[0], args[1], block);
200-
case 3: return (IRubyObject) ensureTarget3().invokeExact(context, self, clazz, name, args[0], args[1], args[2], block);
254+
case 0: return call(context, self, clazz, name, block);
255+
case 1: return call(context, self, clazz, name, args[0], block);
256+
case 2: return call(context, self, clazz, name, args[0], args[1], block);
257+
case 3: return call(context, self, clazz, name, args[0], args[1], args[2], block);
201258
default:
202259
throw new RuntimeException("invalid arity for call: " + arity);
203260
}

core/src/main/java/org/jruby/internal/runtime/methods/InvokeDynamicMethodFactory.java

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
import java.util.HashMap;
4545
import java.util.List;
4646
import java.util.Map;
47-
import java.util.concurrent.Callable;
47+
import java.util.function.Supplier;
4848

4949
import org.jruby.Ruby;
5050
import org.jruby.anno.JavaMethodDescriptor;
@@ -116,7 +116,7 @@ public DynamicMethod getAnnotatedMethod(final RubyModule implementationClass, fi
116116
notImplemented = notImplemented || desc.anno.notImplemented();
117117
}
118118

119-
Callable<MethodHandle>[] generators = buildAnnotatedMethodHandles(implementationClass.getRuntime(), descs, implementationClass);
119+
Supplier<MethodHandle>[] generators = buildAnnotatedMethodHandles(implementationClass.getRuntime(), descs, implementationClass);
120120

121121
return new HandleMethod(
122122
implementationClass,
@@ -137,14 +137,14 @@ public DynamicMethod getAnnotatedMethod(final RubyModule implementationClass, fi
137137
generators[4]);
138138
}
139139

140-
private Callable<MethodHandle>[] buildAnnotatedMethodHandles(Ruby runtime, List<JavaMethodDescriptor> descs, RubyModule implementationClass) {
140+
private Supplier<MethodHandle>[] buildAnnotatedMethodHandles(Ruby runtime, List<JavaMethodDescriptor> descs, RubyModule implementationClass) {
141141
int min = Integer.MAX_VALUE;
142142
int max = 0;
143143

144144
// FIXME: Using desc.anno.name()[0] for super may super up the wrong name
145145
final String rubyName = descs.get(0).rubyName;
146146

147-
Callable<MethodHandle>[] targets = new Callable[5];
147+
Supplier<MethodHandle>[] targets = new Supplier[5];
148148

149149
for (JavaMethodDescriptor desc: descs) {
150150
MethodHandle method;
@@ -155,7 +155,7 @@ private Callable<MethodHandle>[] buildAnnotatedMethodHandles(Ruby runtime, List<
155155
method = Binder.from(desc.returnClass, desc.declaringClass, desc.parameters).invokeVirtualQuiet(LOOKUP, desc.name);
156156
}
157157

158-
Callable<MethodHandle> target = adaptHandle(method, runtime, desc.actualRequired, desc.required, desc.optional, desc.rest, rubyName, desc.declaringClass, desc.isStatic, desc.hasContext, desc.hasBlock, desc.anno.frame(), implementationClass);
158+
Supplier<MethodHandle> target = adaptHandle(method, runtime, desc.actualRequired, desc.required, desc.optional, desc.rest, rubyName, desc.declaringClass, desc.isStatic, desc.hasContext, desc.hasBlock, desc.anno.frame(), implementationClass);
159159
int specificArity = -1;
160160
if (desc.required < 4 && desc.optional == 0 && !desc.rest) {
161161
if (desc.required == 0) {
@@ -284,27 +284,22 @@ public static MethodHandle finishAdapting(final SmartBinder binder, final RubyMo
284284
return target;
285285
}
286286

287-
public static Callable<MethodHandle> adaptHandle(final MethodHandle method, final Ruby runtime, final int actualRequired, final int required, final int optional, final boolean rest, final String rubyName, final Class declaringClass, final boolean isStatic, final boolean hasContext, final boolean hasBlock, final boolean frame, final RubyModule implementationClass) {
288-
return new Callable<MethodHandle>() {
289-
@Override
290-
public MethodHandle call() throws Exception {
291-
//Class returnClass = method.type().returnType();
292-
293-
int specificArity = -1;
294-
if (optional == 0 && !rest) {
295-
if (required == 0) {
296-
if (actualRequired <= 3) {
297-
specificArity = actualRequired;
298-
}
299-
} else if (required >= 0 && required <= 3) {
300-
specificArity = required;
287+
public static Supplier<MethodHandle> adaptHandle(final MethodHandle method, final Ruby runtime, final int actualRequired, final int required, final int optional, final boolean rest, final String rubyName, final Class declaringClass, final boolean isStatic, final boolean hasContext, final boolean hasBlock, final boolean frame, final RubyModule implementationClass) {
288+
return () -> {
289+
int specificArity = -1;
290+
if (optional == 0 && !rest) {
291+
if (required == 0) {
292+
if (actualRequired <= 3) {
293+
specificArity = actualRequired;
301294
}
295+
} else if (required >= 0 && required <= 3) {
296+
specificArity = required;
302297
}
298+
}
303299

304-
SmartBinder targetBinder = getBinder(specificArity, isStatic, hasContext, hasBlock);
300+
SmartBinder targetBinder = getBinder(specificArity, isStatic, hasContext, hasBlock);
305301

306-
return finishAdapting(targetBinder, implementationClass, rubyName, method, declaringClass, runtime, isStatic, frame);
307-
}
302+
return finishAdapting(targetBinder, implementationClass, rubyName, method, declaringClass, runtime, isStatic, frame);
308303
};
309304
}
310305

core/src/main/java/org/jruby/ir/targets/indy/Bootstrap.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,11 +1096,11 @@ static MethodHandle buildNativeHandle(InvokeSite site, CacheEntry entry, boolean
10961096
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
10971097
LOG.info(site.name() + "\tbound directly to JVM method " + Bootstrap.logMethod(method));
10981098
}
1099-
}
11001099

1101-
JRubyMethod anno = nativeCall.getMethod().getAnnotation(JRubyMethod.class);
1102-
if (anno != null && anno.frame()) {
1103-
mh = InvocationLinker.wrapWithFrameOnly(site.signature, entry.sourceModule, site.name(), mh);
1100+
JRubyMethod anno = nativeCall.getMethod().getAnnotation(JRubyMethod.class);
1101+
if (anno != null && anno.frame()) {
1102+
mh = InvocationLinker.wrapWithFrameOnly(site.signature, entry.sourceModule, site.name(), mh);
1103+
}
11041104
}
11051105
}
11061106
}

core/src/main/java/org/jruby/ir/targets/indy/InvokeSite.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ private IRubyObject performIndirectCall(ThreadContext context, IRubyObject self,
252252
if (literalClosure) {
253253
try {
254254
if (passSymbol) {
255-
return method.call(context, self, sourceModule, methodName, Helpers.arrayOf(context.runtime.newSymbol(methodName), args), block);
255+
return method.call(context, self, sourceModule, "method_missing", Helpers.arrayOf(context.runtime.newSymbol(methodName), args), block);
256256
} else {
257257
return method.call(context, self, sourceModule, methodName, args, block);
258258
}

0 commit comments

Comments
 (0)