Skip to content

Commit 4fd9292

Browse files
committed
Change the way we do invokewithcapture.
This avoids a bunch of nested runloops and all the problems that come with them. Re-working this, once a tweak is done in Rakudo, gets rid of the couple of exit-time SEGVs in the md-nqp branch.
1 parent ed35b15 commit 4fd9292

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

src/QAST/Operations.nqp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,24 @@ QAST::Operations.add_core_pirop_mapping('captureexistsnamed', 'exists', 'IQs');
10721072
QAST::Operations.add_core_pirop_mapping('captureposprimspec', 'captureposprimspec', 'IPi');
10731073

10741074
# Multiple dispatch related.
1075-
QAST::Operations.add_core_pirop_mapping('invokewithcapture', 'invoke_with_capture', 'PPP');
1075+
QAST::Operations.add_core_op('invokewithcapture', -> $qastcomp, $op {
1076+
unless $op.list == 2 {
1077+
nqp::die("The 'invokewithcapture' op requires two children");
1078+
}
1079+
my $pos_reg := $*REGALLOC.fresh_p();
1080+
my $nam_reg := $*REGALLOC.fresh_p();
1081+
my $res_reg := $*REGALLOC.fresh_p();
1082+
my $inv_post := $qastcomp.coerce($qastcomp.as_post($op[0]), 'P');
1083+
my $cap_post := $qastcomp.coerce($qastcomp.as_post($op[1]), 'P');
1084+
my $ops := PIRT::Ops.new();
1085+
$ops.push($inv_post);
1086+
$ops.push($cap_post);
1087+
$ops.push_pirop('deconstruct_capture', $cap_post.result, $pos_reg, $nam_reg);
1088+
$ops.push_pirop('call', $inv_post.result, $pos_reg ~ ' :flat',
1089+
$nam_reg ~ ' :flat :named', :result($res_reg));
1090+
$ops.result($res_reg);
1091+
$ops
1092+
});
10761093
QAST::Operations.add_core_pirop_mapping('multicacheadd', 'multi_cache_add', 'PPPP');
10771094
QAST::Operations.add_core_pirop_mapping('multicachefind', 'multi_cache_find', 'PPP');
10781095

src/ops/nqp.ops

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ PMC *compiling_scs = NULL;
5454
* number of nested enable/disable we are in. */
5555
INTVAL sc_write_barrier_off_depth = 0;
5656

57+
/* Empty hash, used in deconstruct op. */
58+
static PMC *empty_hash = NULL;
59+
5760
/* SC write barrier for objects. */
5861
static void SC_write_barrier_obj(PARROT_INTERP, PMC *obj) {
5962
if (!sc_write_barrier_off_depth && VTABLE_get_bool(interp, compiling_scs)) {
@@ -340,6 +343,10 @@ inline op nqp_dynop_setup() :base_core {
340343
nfa_nextst = Parrot_pmc_new(interp, enum_class_ResizableIntegerArray);
341344
Parrot_pmc_gc_register(interp, nfa_nextst);
342345

346+
/* Create and anchor empty hash. */
347+
empty_hash = Parrot_pmc_new(interp, enum_class_Hash);
348+
Parrot_pmc_gc_register(interp, empty_hash);
349+
343350
/* Mark initialized. */
344351
initialized = 1;
345352
}
@@ -1576,14 +1583,64 @@ Invokes the specified target with the specified capture.
15761583
inline op invoke_with_capture(out PMC, in PMC, in PMC) :base_core {
15771584
PMC *arg_copy = VTABLE_clone(interp, $3);
15781585
PMC *result;
1579-
PMC *prev_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
1586+
/*PMC *prev_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));*/
15801587
Parrot_pcc_invoke_from_sig_object(interp, $2, arg_copy);
15811588
result = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
1582-
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), prev_ctx);
1589+
/*Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), prev_ctx);*/
15831590
$1 = VTABLE_get_pmc_keyed_int(interp, result, 0);
15841591
}
15851592

15861593

1594+
/*
1595+
1596+
=item deconstruct_capture()
1597+
1598+
Puts something that will flatten to the position part of the capture in $1
1599+
into $2, and soemthing that will flatten to the named part into $3.
1600+
1601+
=cut
1602+
1603+
*/
1604+
inline op deconstruct_capture(invar PMC, out PMC, out PMC) :base_core {
1605+
PMC *capture = $1;
1606+
if (capture->vtable->base_type == enum_class_CallContext) {
1607+
Hash *nameds;
1608+
INTVAL has_nameds;
1609+
1610+
/* The call context itself will do for the positionals. */
1611+
$2 = capture;
1612+
1613+
/* See if there are any nameds */
1614+
GETATTR_CallContext_hash(interp, capture, nameds);
1615+
has_nameds = nameds && Parrot_hash_size(interp, nameds) ? 1 : 0;
1616+
1617+
/* If there's a named part, create a hash with the values. */
1618+
if (has_nameds) {
1619+
PMC *result = Parrot_pmc_new(interp, enum_class_Hash);
1620+
PMC *named_names = VTABLE_get_attr_str(interp, capture,
1621+
Parrot_str_new_constant(interp, "named"));
1622+
INTVAL n = VTABLE_elements(interp, named_names);
1623+
INTVAL i;
1624+
for (i = 0; i < n; i++) {
1625+
STRING *name = VTABLE_get_string_keyed_int(interp, named_names, i);
1626+
VTABLE_set_pmc_keyed_str(interp, result, name,
1627+
VTABLE_get_pmc_keyed_str(interp, capture, name));
1628+
}
1629+
$3 = result;
1630+
}
1631+
1632+
/* Otherwise, use empty hash. */
1633+
else {
1634+
$3 = empty_hash;
1635+
}
1636+
}
1637+
else {
1638+
$2 = $1;
1639+
$3 = empty_hash;
1640+
}
1641+
}
1642+
1643+
15871644
/*
15881645

15891646
=item multi_cache_add()

0 commit comments

Comments
 (0)