Ticket #1138 (closed todo: fixed)

Opened 5 years ago

Last modified 4 years ago

Create a 'vivify' opcode

Reported by: Austin_Hastings Owned by:
Priority: normal Milestone:
Component: core Version: 1.7.0
Severity: medium Keywords:
Cc: Language:
Patch status: Platform:

Description

PCT generates a lot of code that looks like:

    find_lex $P99, '$var'
    unless_null $P99, vivify_22
    $P99 = new 'Undef'
vivify_22:

In kakapo.pir, a library of 21872 lines (wc-l) of NQP generated pir, there were 1381 occurrences of this pattern. (Grep ", vivify_" | wc -l)

This is 6.3% of the total file size, including infrastructure. It's surely a larger fraction of the "real" code. (In fact, that's one of three lines the pattern uses. So the pattern is actually something like 19% of the total lines in the file.)

Converting these two opcodes:

    unless-null P, IC
    new P, SC

into 1 opcode:

    vivify P, SC

would reduce the pir size by that 6%, since it eliminates one of the lines entirely. Per a conversation with chromatic this evening, we expect about a 2-3% reduction is pbc size (pir lines != opcode words) and a corresponding 2-3% increase in execution speed.

Change History

  Changed 5 years ago by pmichaud

Several related points.

First, also take a look at TT #787, which deals with the issue of lvalues in Parrot in general, and is very related to the above code pattern that NQP/PCT generate.

Second, please-please-please note that we're generally deprecating the use of string constants as class/PMC identifiers -- PCT's use of strings there is really a fossil. If we introduce a vivify opcode, it needs to be vivify P, PC .

Third, based on an improved understanding of the Perl 6 specification, NQP and Rakudo will be able to eliminate the above pattern altogether for lexical variables -- i.e., we can guarantee that lexicals will be initialized to Undef at declaration time, and thus all lexical lookups will be able to avoid the "vivify if null" sequence altogether. We'll still need the vivify sequence for aggregate lookups (hashes/arrays), but there we should also deal with the issue of lvalue vivification and value assignment.

Hope this can spark some useful discussion.

Pm

follow-up: ↓ 3   Changed 5 years ago by pmichaud

Having just written further details on TT #787, I thought I'd add a note here: In general I'm in favor of coming up with opcode(s) that avoid or simplify the "create if null" sequences that NQP/PCT currently end up generating. But I'm opposed to the "vivify" opcode as proposed above for two reasons:

1. It's misnamed -- it's really just defaulting a null PMC to a value, it doesn't "vivify" a lexical symbol or aggregate element in the sense of "create and bind" that HLLs normally have.

2. I think we can come up with a far more powerful set of opcodes than this.

Just brainstorming a bit: I'm thinking that what might be very powerful would be separate "fetch" and "vivify" opcodes that handle nearly all of the rvalue and lvalue scenarios we currently have. The generic form of each would be:

    $P0 = fetch $P1[key], $P2     # rvalue fetch
    $P0 = vivify $P1[key], $P2    # lvalue fetch

The first form does a lookup of 'key' in an aggregate $P1, if found it returns it, otherwise it returns $P2. The second form is similar, but if 'key' isn't found then we clone $P2 and bind the aggregate to the clone before returning it.

Since lexpads and namespaces effectively act as hashes, these two opcodes should be sufficient for nearly all lexical, package, and keyed variable accesses. For example:

    # at beginning of sub
    .local pmc lexpad, undef
    $P0 = getinterp
    lexpad = $P0['lexpad', 0]
    undef = new ['Undef']

    # say($foo)
    $P99 = fetch lexpad['$foo'], undef
    say $P99
    
    # $foo = 4
    $P99 = vivify lexpad['$foo'], undef
    assign $P99, 4

Clearly these would also work well for namespace and aggregates:

    # $ABC::Test::xyz = 'hello';
    $P0 = get_namespace ['ABC';'Test']
    $P99 = vivify $P0['$xyz'], undef
    assign $P99, 'hello'

    # %hash['key'] = $a
    $P100 = vivify lexpad['%hash'], hash
    $P101 = vivify $P0['key'], undef
    $P102 = fetch  lexpad['$a'], undef
    assign $P101, $P102

Here I've proposed that the last argument to 'fetch' and 'vivify' be used as values to be cloned instead of types to be created -- I think that cloning a default value gives us more flexibility in what that default can be (e.g., initial values or properties already in place).

Thoughts welcomed on the above. If fetch and vivify were made available along the lines I've given here it would greatly simplify variable access in PCT and be far more efficient than what we've been generating.

Pm

in reply to: ↑ 2   Changed 5 years ago by pmichaud

There's a slight flaw in my proposal above with using 'fetch' and 'vivify' on lexicals -- a LexPad PMC only holds the lexicals for the current sub, and not any of its outer subs. I can think of three easy-ish amendments to the proposal that resolve this:

(1) Provide "fetch_lex" and "vivify_lex" forms of the opcodes for working with lexicals.

(2) Create a PMC type that provides a hash interface for an entire lexical scope (instead of just the current lexpad), and use that as the argument to 'fetch' and 'vivify'.

(3) Have a special sentinel value for the aggregate parameter in 'fetch' and 'vivify' that indicates lexical scopes are to be used:

.const PMC lexical = ...some sentinel...

$P0 = fetch lexical$a?, default

Pm

  Changed 5 years ago by whiteknight

There are several vivify opcodes in Parrot now, all listed as experimental. To my knowledge, none of these opcodes have any test coverage, and NQP doesn't output these in it's generated code.

Can we get a update about what the status is of this ticket? Are the vivify ops in the repo what this ticket needs? If so, does NQP use them? Is anybody able to write tests for them? Are they going to stay experimental?

  Changed 5 years ago by pmichaud

On Tue, Mar 30, 2010 at 12:19:40AM -0000, Parrot wrote:
>  There are several vivify opcodes in Parrot now, all listed as
>  experimental. To my knowledge, none of these opcodes have any test
>  coverage, and NQP doesn't output these in it's generated code.

PAST needs to be reworked to be able to take advantage of vivify.
I have not had an opportunity to do this yet -- been too busy
resolving other issues (and the current PAST code works fine,
albeit generating fairly ugly code).

The vivify opcode has extensive test coverage in t/op/vivify.t
(the tests were committed as part of the patch that added vivify).

Pm

  Changed 4 years ago by cotto

  • status changed from new to closed
  • resolution set to fixed

Now that we have a vivify opcode, the original purpose of this ticket seems to have been fulfilled. I'm marking it as fixed.

Note: See TracTickets for help on using tickets.