Skip to content

Commit 76c2df8

Browse files
committedJul 17, 2018
Merge non-RubyHash parts of improve_kwargs branch.
This does not include @ChrisBr work on open addressing Hash. Merge commit '4116c0c6da725d7586569eb62797b2091df6db71'
2 parents 772832a + 4116c0c commit 76c2df8

File tree

5 files changed

+76
-66
lines changed

5 files changed

+76
-66
lines changed
 

‎core/src/main/java/org/jruby/RubyHash.java

+17
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,23 @@ private <T> void visitLimited(ThreadContext context, VisitorWithState visitor, l
692692
if (count > 0) throw concurrentModification();
693693
}
694694

695+
public <T> boolean allSymbols() {
696+
int startGeneration = generation;
697+
// visit not more than size entries
698+
RubyHashEntry head = this.head;
699+
for (RubyHashEntry entry = head.nextAdded; entry != head; entry = entry.nextAdded) {
700+
if (startGeneration != generation) {
701+
startGeneration = generation;
702+
entry = head.nextAdded;
703+
if (entry == head) break;
704+
}
705+
if (entry != null && entry.isLive()) {
706+
if (!(entry.key instanceof RubySymbol)) return false;
707+
}
708+
}
709+
return true;
710+
}
711+
695712
/* ============================
696713
* End of hash internals
697714
* ============================

‎core/src/main/java/org/jruby/compiler/MethodJITTask.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,7 @@ public void run() {
130130
variable,
131131
method.getIRScope(),
132132
method.getVisibility(),
133-
method.getImplementationClass(),
134-
method.getIRScope().receivesKeywordArgs()));
133+
method.getImplementationClass()));
135134

136135
} else {
137136
// also specific-arity
@@ -143,8 +142,7 @@ public void run() {
143142
entry.getKey(),
144143
method.getIRScope(),
145144
method.getVisibility(),
146-
method.getImplementationClass(),
147-
method.getIRScope().receivesKeywordArgs()));
145+
method.getImplementationClass()));
148146
break; // FIXME: only supports one arity
149147
}
150148
}

‎core/src/main/java/org/jruby/internal/runtime/methods/CompiledIRMethod.java

+6-32
Original file line numberDiff line numberDiff line change
@@ -25,50 +25,28 @@ public class CompiledIRMethod extends AbstractIRMethod {
2525
private final MethodHandle specific;
2626
private final int specificArity;
2727

28-
private final boolean hasKwargs;
29-
3028
public CompiledIRMethod(MethodHandle variable, IRScope method, Visibility visibility,
31-
RubyModule implementationClass, boolean hasKwargs) {
32-
this(variable, null, -1, method, visibility, implementationClass, hasKwargs);
29+
RubyModule implementationClass) {
30+
this(variable, null, -1, method, visibility, implementationClass);
3331
}
3432

3533
public CompiledIRMethod(MethodHandle variable, MethodHandle specific, int specificArity, IRScope method,
36-
Visibility visibility, RubyModule implementationClass, boolean hasKwargs) {
34+
Visibility visibility, RubyModule implementationClass) {
3735
super(method, visibility, implementationClass);
3836

39-
if (hasKwargs) {
40-
MethodType type = variable.type();
41-
int params = type.parameterCount();
42-
MethodHandle frobnicate = Binder
43-
.from(type.changeReturnType(IRubyObject[].class))
44-
.dropLast(params - 4)
45-
.drop(1, 2)
46-
.append(signature)
47-
.invoke(FROBNICATE);
48-
this.variable = Binder
49-
.from(type)
50-
.fold(frobnicate)
51-
.permute(type.parameterType(params - 1) == Block.class ? new int[] {1, 2, 3, 0, 5, 6, 7, 8} : new int[] {1, 2, 3, 0, 5, 6, 7})
52-
.invoke(variable);
53-
} else {
54-
this.variable = variable;
55-
}
37+
38+
this.variable = variable;
5639
this.specific = specific;
5740
// deopt unboxing if we have to process kwargs hash (although this really has nothing to do with arg
5841
// unboxing -- it was a simple path to hacking this in).
59-
this.specificArity = hasKwargs ? -1 : specificArity;
42+
this.specificArity = method.receivesKeywordArgs() ? -1 : specificArity;
6043
this.method.getStaticScope().determineModule();
61-
this.hasKwargs = hasKwargs;
6244

6345
assert method.hasExplicitCallProtocol();
6446

6547
setHandle(variable);
6648
}
6749

68-
private static final MethodHandle FROBNICATE = Binder
69-
.from(IRubyObject[].class, ThreadContext.class, IRubyObject[].class, Signature.class)
70-
.invokeStaticQuiet(MethodHandles.lookup(), IRRuntimeHelpers.class, "frobnicateKwargsArgument");
71-
7250
public MethodHandle getHandleFor(int arity) {
7351
if (specificArity != -1 && arity == specificArity) {
7452
return specific;
@@ -232,8 +210,4 @@ public String toString() {
232210
return getClass().getName() + '@' + Integer.toHexString(hashCode()) + ' ' + method + ' ' + getSignature();
233211
}
234212

235-
public boolean hasKwargs() {
236-
return hasKwargs;
237-
}
238-
239213
}

‎core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java

+40-30
Original file line numberDiff line numberDiff line change
@@ -536,40 +536,50 @@ public static void checkArity(ThreadContext context, StaticScope scope, Object[]
536536
}
537537
}
538538

539-
public static IRubyObject[] frobnicateKwargsArgument(ThreadContext context, IRubyObject[] args,
540-
org.jruby.runtime.Signature signature) {
541-
return frobnicateKwargsArgument(context, args, signature.required());
542-
}
543-
544539
public static IRubyObject[] frobnicateKwargsArgument(ThreadContext context, IRubyObject[] args, int requiredArgsCount) {
545540
// No kwarg because required args slurp them up.
546-
return args.length <= requiredArgsCount ? args : frobnicateKwargsArgument(context, args);
547-
}
541+
int length = args.length;
542+
543+
if (length <= requiredArgsCount) return args;
544+
545+
final IRubyObject maybeKwargs = toHash(args[length - 1], context);
548546

549-
private static IRubyObject[] frobnicateKwargsArgument(final ThreadContext context, IRubyObject[] args) {
550-
final IRubyObject kwargs = toHash(args[args.length - 1], context);
551-
if (kwargs != null) {
552-
if (kwargs.isNil()) { // nil on to_hash is supposed to keep itself as real value so we need to make kwargs hash
547+
if (maybeKwargs != null) {
548+
if (maybeKwargs.isNil()) { // nil on to_hash is supposed to keep itself as real value so we need to make kwargs hash
553549
return ArraySupport.newCopy(args, RubyHash.newSmallHash(context.runtime));
554550
}
555551

556-
DivvyKeywordsVisitor visitor = new DivvyKeywordsVisitor();
557-
// We know toHash makes null, nil, or Hash
558-
((RubyHash) kwargs).visitAll(context, visitor, null);
552+
RubyHash kwargs = (RubyHash) maybeKwargs;
559553

560-
if (visitor.syms == null) {
561-
// no symbols, use empty kwargs hash
562-
visitor.syms = RubyHash.newSmallHash(context.runtime);
554+
if (kwargs.allSymbols()) {
555+
args[length - 1] = kwargs;
556+
} else {
557+
args = homogenizeKwargs(context, args, kwargs);
563558
}
559+
}
564560

565-
if (visitor.others != null) { // rest args exists too expand args
566-
IRubyObject[] newArgs = new IRubyObject[args.length + 1];
567-
System.arraycopy(args, 0, newArgs, 0, args.length);
568-
args = newArgs;
569-
args[args.length - 2] = visitor.others; // opt args
570-
}
571-
args[args.length - 1] = visitor.syms; // kwargs hash
561+
return args;
562+
}
563+
564+
private static IRubyObject[] homogenizeKwargs(ThreadContext context, IRubyObject[] args, RubyHash kwargs) {
565+
DivvyKeywordsVisitor visitor = new DivvyKeywordsVisitor();
566+
567+
// We know toHash makes null, nil, or Hash
568+
kwargs.visitAll(context, visitor, null);
569+
570+
if (visitor.syms == null) {
571+
// no symbols, use empty kwargs hash
572+
visitor.syms = RubyHash.newSmallHash(context.runtime);
572573
}
574+
575+
if (visitor.others != null) { // rest args exists too expand args
576+
IRubyObject[] newArgs = new IRubyObject[args.length + 1];
577+
System.arraycopy(args, 0, newArgs, 0, args.length);
578+
args = newArgs;
579+
args[args.length - 2] = visitor.others; // opt args
580+
}
581+
args[args.length - 1] = visitor.syms; // kwargs hash
582+
573583
return args;
574584
}
575585

@@ -1356,7 +1366,7 @@ public static DynamicMethod newInterpretedModuleBody(ThreadContext context, IRSc
13561366
@JIT
13571367
public static DynamicMethod newCompiledModuleBody(ThreadContext context, MethodHandle handle, IRScope irModule, Object rubyContainer) {
13581368
RubyModule newRubyModule = newRubyModuleFromIR(context, irModule, rubyContainer);
1359-
return new CompiledIRMethod(handle, irModule, Visibility.PUBLIC, newRubyModule, false);
1369+
return new CompiledIRMethod(handle, irModule, Visibility.PUBLIC, newRubyModule);
13601370
}
13611371

13621372
private static RubyModule newRubyModuleFromIR(ThreadContext context, IRScope irModule, Object rubyContainer) {
@@ -1380,7 +1390,7 @@ public static DynamicMethod newInterpretedClassBody(ThreadContext context, IRSco
13801390
public static DynamicMethod newCompiledClassBody(ThreadContext context, MethodHandle handle, IRScope irClassBody, Object container, Object superClass) {
13811391
RubyModule newRubyClass = newRubyClassFromIR(context.runtime, irClassBody, superClass, container);
13821392

1383-
return new CompiledIRMethod(handle, irClassBody, Visibility.PUBLIC, newRubyClass, false);
1393+
return new CompiledIRMethod(handle, irClassBody, Visibility.PUBLIC, newRubyClass);
13841394
}
13851395

13861396
public static RubyModule newRubyClassFromIR(Ruby runtime, IRScope irClassBody, Object superClass, Object container) {
@@ -1431,7 +1441,7 @@ public static void defCompiledClassMethod(ThreadContext context, MethodHandle ha
14311441
RubyClass rubyClass = checkClassForDef(context, method, obj);
14321442

14331443
// FIXME: needs checkID and proper encoding to force hard symbol
1434-
rubyClass.addMethod(methodName.idString(), new CompiledIRMethod(handle, method, Visibility.PUBLIC, rubyClass, method.receivesKeywordArgs()));
1444+
rubyClass.addMethod(methodName.idString(), new CompiledIRMethod(handle, method, Visibility.PUBLIC, rubyClass));
14351445
if (!rubyClass.isRefinement()) {
14361446
// FIXME: needs checkID and proper encoding to force hard symbol
14371447
obj.callMethod(context, "singleton_method_added", methodName);
@@ -1442,7 +1452,7 @@ public static void defCompiledClassMethod(ThreadContext context, MethodHandle ha
14421452
public static void defCompiledClassMethod(ThreadContext context, MethodHandle variable, MethodHandle specific, int specificArity, IRScope method, IRubyObject obj) {
14431453
RubyClass rubyClass = checkClassForDef(context, method, obj);
14441454

1445-
rubyClass.addMethod(method.getId(), new CompiledIRMethod(variable, specific, specificArity, method, Visibility.PUBLIC, rubyClass, method.receivesKeywordArgs()));
1455+
rubyClass.addMethod(method.getId(), new CompiledIRMethod(variable, specific, specificArity, method, Visibility.PUBLIC, rubyClass));
14461456

14471457
if (!rubyClass.isRefinement()) obj.callMethod(context, "singleton_method_added", method.getName());
14481458
}
@@ -1485,7 +1495,7 @@ public static void defCompiledInstanceMethod(ThreadContext context, MethodHandle
14851495
Visibility currVisibility = context.getCurrentVisibility();
14861496
Visibility newVisibility = Helpers.performNormalMethodChecksAndDetermineVisibility(runtime, clazz, methodName, currVisibility);
14871497

1488-
DynamicMethod newMethod = new CompiledIRMethod(handle, method, newVisibility, clazz, method.receivesKeywordArgs());
1498+
DynamicMethod newMethod = new CompiledIRMethod(handle, method, newVisibility, clazz);
14891499

14901500
// FIXME: needs checkID and proper encoding to force hard symbol
14911501
Helpers.addInstanceMethod(clazz, methodName, newMethod, currVisibility, context, runtime);
@@ -1500,7 +1510,7 @@ public static void defCompiledInstanceMethod(ThreadContext context, MethodHandle
15001510
Visibility currVisibility = context.getCurrentVisibility();
15011511
Visibility newVisibility = Helpers.performNormalMethodChecksAndDetermineVisibility(runtime, clazz, methodName, currVisibility);
15021512

1503-
DynamicMethod newMethod = new CompiledIRMethod(variable, specific, specificArity, method, newVisibility, clazz, method.receivesKeywordArgs());
1513+
DynamicMethod newMethod = new CompiledIRMethod(variable, specific, specificArity, method, newVisibility, clazz);
15041514

15051515
// FIXME: needs checkID and proper encoding to force hard symbol
15061516
Helpers.addInstanceMethod(clazz, methodName, newMethod, currVisibility, context, runtime);

‎core/src/main/java/org/jruby/ir/targets/JVMVisitor.java

+11
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,17 @@ protected void emitScope(IRScope scope, String name, Signature signature, boolea
205205
syntheticEndForStart.put(currentBlockStart, syntheticEnd);
206206
}
207207

208+
if (scope instanceof IRMethod) {
209+
if (scope.receivesKeywordArgs()) {
210+
// pre-frobnicate the args on the way in
211+
m.loadContext();
212+
m.loadArgs();
213+
m.adapter.pushInt(scope.getStaticScope().getSignature().required());
214+
m.invokeIRHelper("frobnicateKwargsArgument", sig(IRubyObject[].class, ThreadContext.class, IRubyObject[].class, int.class));
215+
m.storeArgs();
216+
}
217+
}
218+
208219
for (BasicBlock bb: bbs) {
209220
org.objectweb.asm.Label start = jvm.methodData().getLabel(bb.getLabel());
210221
Label rescueLabel = exceptionTable.get(bb);

0 commit comments

Comments
 (0)
Please sign in to comment.