Skip to content

Commit 20547c3

Browse files
committed
Send indirect calls through invokedynamic.
Not expecting a performance change from this, but it makes code gen a bit simpler/better/uniformer.
1 parent 1cc2d3e commit 20547c3

File tree

2 files changed

+89
-24
lines changed

2 files changed

+89
-24
lines changed

src/vm/jvm/QAST/Compiler.nqp

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,7 @@ sub process_args($qastcomp, @children, $il, $first, :$inv_temp) {
11111111
# Return callsite index (which may create it if needed).
11121112
return [$*CODEREFS.get_callsite_idx(@callsite, @argnames), $arg_array];
11131113
}
1114-
sub process_args_onto_stack($qastcomp, @children, $il, :$obj_first) {
1114+
sub process_args_onto_stack($qastcomp, @children, $il, :$obj_first, :$inv_first) {
11151115
# Make sure we do positionals before nameds.
11161116
my @pos;
11171117
my @named;
@@ -1129,7 +1129,7 @@ sub process_args_onto_stack($qastcomp, @children, $il, :$obj_first) {
11291129
my @argnames;
11301130
my int $i := 0;
11311131
while $i < +@order {
1132-
my $arg_res := $i == 0 && $obj_first
1132+
my $arg_res := $i == 0 && ($obj_first || $inv_first)
11331133
?? $qastcomp.as_jast(@order[$i], :want($RT_OBJ))
11341134
!! $qastcomp.as_jast(@order[$i]);
11351135
$il.append($arg_res.jast);
@@ -1146,15 +1146,17 @@ sub process_args_onto_stack($qastcomp, @children, $il, :$obj_first) {
11461146
nqp::push(@arg_jtypes, jtype($arg_res.type));
11471147
}
11481148

1149-
my int $flags := 0;
1150-
if @order[$i].flat {
1151-
$flags := @order[$i].named ?? 24 !! 16;
1152-
}
1153-
elsif @order[$i].named -> $name {
1154-
$flags := 8;
1155-
nqp::push(@argnames, $name);
1149+
unless $i == 0 && $inv_first {
1150+
my int $flags := 0;
1151+
if @order[$i].flat {
1152+
$flags := @order[$i].named ?? 24 !! 16;
1153+
}
1154+
elsif @order[$i].named -> $name {
1155+
$flags := 8;
1156+
nqp::push(@argnames, $name);
1157+
}
1158+
nqp::push(@callsite, arg_type($type) + $flags);
11561159
}
1157-
nqp::push(@callsite, arg_type($type) + $flags);
11581160

11591161
$i++;
11601162
}
@@ -1190,23 +1192,26 @@ QAST::OperationsJAST.add_core_op('call', sub ($qastcomp, $node) {
11901192

11911193
# Otherwise, it's an indirect call.
11921194
else {
1193-
# Compile the thing to invoke.
1195+
# Ensure we have a thing to invoke.
11941196
nqp::die("A 'call' node must have a name or at least one child") unless +@($node) >= 1;
1195-
my $invokee := $qastcomp.as_jast($node[0], :want($RT_OBJ));
1196-
$il.append($invokee.jast);
1197-
1198-
# Process arguments.
1199-
my @argstuff := process_args($qastcomp, @($node), $il, $node.name eq "" ?? 1 !! 0);
1197+
1198+
# Proces arguments, making sure first one is an object (since that is
1199+
# the thing to invoke).
1200+
my @argstuff := process_args_onto_stack($qastcomp, @($node), $il, :inv_first);
12001201
my $cs_idx := @argstuff[0];
12011202
$*STACK.spill_to_locals($il);
1202-
1203-
# Emit the call.
1204-
$*STACK.obtain($il, $invokee);
1205-
$il.append(JAST::PushIndex.new( :value($cs_idx) ));
1206-
$il.append(JAST::Instruction.new( :op('aload'), @argstuff[1] ));
1203+
1204+
# Emit the call, using the same thread context trick. The first thing
1205+
# will be invoked.
12071206
$il.append(JAST::Instruction.new( :op('aload_1') ));
1208-
$il.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'invoke',
1209-
'Void', $TYPE_SMO, 'Integer', "[$TYPE_OBJ", $TYPE_TC ));
1207+
$*STACK.obtain($il, |@argstuff[1]) if @argstuff[1];
1208+
$il.append(JAST::InvokeDynamic.new(
1209+
'indcall', 'V', @argstuff[2],
1210+
'org/perl6/nqp/runtime/IndyBootstrap', 'indcall',
1211+
[
1212+
JAST::PushIndex.new( :value($cs_idx) )
1213+
]
1214+
));
12101215
}
12111216

12121217
# Load result onto the stack, unless in void context.
@@ -1234,7 +1239,7 @@ QAST::OperationsJAST.add_core_op('callmethod', -> $qastcomp, $node {
12341239
# calling.
12351240
if $node.name ne '' {
12361241
# Process arguments and force them into locals.
1237-
my @argstuff := process_args_onto_stack($qastcomp, @children, $il);
1242+
my @argstuff := process_args_onto_stack($qastcomp, @children, $il, :obj_first);
12381243
my $cs_idx := @argstuff[0];
12391244
$*STACK.spill_to_locals($il);
12401245

src/vm/jvm/runtime/org/perl6/nqp/runtime/IndyBootstrap.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,66 @@ public static void lexotic_s(long target, SixModelObject boxType, ThreadContext
240240
throw throwee;
241241
}
242242

243+
public static CallSite indcall(Lookup caller, String _, MethodType type, int csIdx) {
244+
try {
245+
/* Look up indirect call invoker method. */
246+
MethodType resType = MethodType.methodType(void.class,
247+
MutableCallSite.class, int.class, ThreadContext.class,
248+
SixModelObject.class, Object[].class);
249+
MethodHandle res = caller.findStatic(IndyBootstrap.class, "indcallInvoker", resType);
250+
251+
/* Create a mutable callsite, and curry the resolver with it and
252+
* the sub name. */
253+
MutableCallSite cs = new MutableCallSite(type);
254+
cs.setTarget(MethodHandles
255+
.insertArguments(res, 0, cs, csIdx)
256+
.asCollector(Object[].class, type.parameterCount() - 2)
257+
.asType(type));
258+
259+
/* Produce callsite. */
260+
return cs;
261+
}
262+
catch (Exception e) {
263+
e.printStackTrace();
264+
throw new RuntimeException(e);
265+
}
266+
}
267+
268+
public static void indcallInvoker(MutableCallSite cs, int csIdx,
269+
ThreadContext tc, SixModelObject invokee, Object... args) {
270+
/* Resolve callsite descriptor. */
271+
CallSiteDescriptor csd = csIdx >= 0
272+
? tc.curFrame.codeRef.staticInfo.compUnit.callSites[csIdx]
273+
: Ops.emptyCallSite;
274+
275+
/* Get the code ref. */
276+
CodeRef cr;
277+
if (invokee instanceof CodeRef) {
278+
cr = (CodeRef)invokee;
279+
}
280+
else {
281+
InvocationSpec is = invokee.st.InvocationSpec;
282+
if (is == null)
283+
throw ExceptionHandling.dieInternal(tc, "Can not invoke this object");
284+
if (is.ClassHandle != null)
285+
cr = (CodeRef)invokee.get_attribute_boxed(tc, is.ClassHandle, is.AttrName, is.Hint);
286+
else
287+
cr = (CodeRef)is.InvocationHandler;
288+
}
289+
290+
/* Make the call. */
291+
try {
292+
cr.staticInfo.mh.invokeExact(tc, cr, csd, args);
293+
}
294+
catch (ControlException e) {
295+
throw e;
296+
}
297+
catch (Throwable e) {
298+
e.printStackTrace();
299+
ExceptionHandling.dieInternal(tc, e);
300+
}
301+
}
302+
243303
public static CallSite methcall(Lookup caller, String _, MethodType type, String name, int csIdx) {
244304
try {
245305
/* Look up methcall resolver method. */

0 commit comments

Comments
 (0)