Dan Sugalski <[EMAIL PROTECTED]> wrote:
> At 5:19 PM +0100 3/19/05, Leopold Toetsch wrote:
>>1) builtin methods are living in a class namespace e.g.
>>
>>   Float."cos"
>>   ParrotIO."open"  # unimplemented

> I'm way out of the loop and may have been dealt with in prior mail,
> but are we doing real method calls for cos() and suchlike things?
> That seems... sub-optimal for speed reasons.

With the help of the PIC it'll translate to an one-time lookup per call
site aka bytecode location. The lookup result is additionally cached in
the method cache, which is pretty fast.

The "method call" will translate eventually to an opcode like:

  call_PP "cos", Px, Py

(we gonna have a fair amount of methods with this signature, so that a
specialized opcode should be ok)

The actual call then looks like:

  pic_cache = $1    # replaces the method name in bytecode
  if ($3->vtable->type == pic_cache->type)
    $2 = (pic_cache->nci.function)(interp, $3)
  else
    // consider ~3 more cache slots
  else
    // lookup the method

The speed overhead compared to a dedicated vtable slot is minimal as
that will call directly the C function - not the NCI wrapper.

A further optimization could inline the function call for e.g. Float.cos

  if ($3->vtable->type == enum_class_Float) {
     FLOATVAL l, r = PMC_num_val($3);
     l = cos(r);
     ...

> I've been thinking it may be worth pulling out some groups of
> semi-commonly used functions that should be fast but still
> PMC-class-specific, and thus not methods, into sub-tables hanging off
> the vtable.

Well, yes I'd like to have the vtable split into pieces. The vtable
structure is just too big and by far not all functionality is needed by
all PMCs:

  sizeof(VTABLE) 604   # 32-bit machine

> ... Most of the semi-high-level string functions (basically
> everything that may be delegated to the charset/encoding layers)
> would be a candidate for this. Possibly the standard trig functions
> too.

I'd say: all that maybe used internally by the interpreter should have a
vtable slot. Trig functions and other stuff can simply be done by a
method call. One advantage is expandability, e.g

  .namespace ["Complex"]
  .sub cos
    ...

is all to override (or create) a new method. During recompilation the
"call_PP" opcode can directly be replaced by another variant that calls
the PIR code from witin the same run-loop, without any delegation PMC
and secondary run-loop.

And the second is: having a vtable for all these functions needs an
opcode too. We have 1500 opcodes and are already hitting compiler limits
e.g. in the switch core. We can't afford to add another bunch of opcodes
to get PMC versions of all the native type opcodes.

The

  call_PP "meth", Px, Py

opcode covers all such methods with that signature. Float.cos might be a
suboptimal example, but we need a lot more library code e.g. $(perldoc
POSIX) and what not. The whole library stuff needs just a namespace and
an implementation either as PIR, NCI, or in a PMC class file. The call
syntax from the PIR level looks like a method call or a plain opcode:

.sub main @MAIN
    .local pmc o, m, cl
    o = getstdout
    $I0 = o."puts"("ok 1\n")
    puts $I0, o, "ok 2\n"
    $I0 = "puts"(o, "ok 3\n")
    m = getattribute o, "puts"
    $I0 = m("ok 4\n")
    cl = getclass "ParrotIO"
    $I0 = cl."puts"(o, "ok 5\n")
.end

leo

Reply via email to