All --

I've talked a few times on the list and on IRC about looking up ops
by name from their oplibs at load time. Last night I finally decided
to write some code to show what I've been talking about.

The attached patch adds a field to the oplib info structure for a
function that takes an op name and returns an integer opcode number
(or -1 if not found).

In addition, it adds some code to ops2c.pl to generate such a function
as a tree of nested switch statements that do a character-by-character
search for the name. I believe this is just about as efficient as we
can expect things to be. We find the op by name in at most one scan
over the op name (failures can fail in as few as one character compare).

On my Athlon 1.4 GHz, I've been measuring about 17 million op-by-name
lookups per second, which I believe is sufficiently fast for load-
time use. For comparison, the same machine gets about 25 mops.

Anyway, I'm attaching the patch for your amusement. This is one part
of the puzzle for building opcode tables at run time. This may go in
after some discussion with Dan, et al.


Regards,

-- Gregor
 ____________________________________________________________________ 
/            Inspiration >> Innovation >> Excellence (TM)            \

   Gregor N. Purdy                         [EMAIL PROTECTED]
   Focus Research, Inc.               http://www.focusresearch.com/
   8080 Beckett Center Drive #203                  513-860-3570 vox
   West Chester, OH 45069                          513-860-3579 fax
\____________________________________________________________________/

[[EMAIL PROTECTED]]$ ping osama.taliban.af
PING osama.taliban.af (68.69.65.68) from 20.1.9.11 : 56 bytes of data.
>From 85.83.77.67: Time to live exceeded
Index: ops2c.pl
===================================================================
RCS file: /home/perlcvs/parrot/ops2c.pl,v
retrieving revision 1.16
diff -a -u -r1.16 ops2c.pl
--- ops2c.pl    30 Jan 2002 04:20:37 -0000      1.16
+++ ops2c.pl    1 Feb 2002 13:36:36 -0000
@@ -46,6 +46,8 @@
 my $header  = "include/$include";
 my $source  = "${base}_ops${suffix}.c";
 
+my $remembered_ops = { };
+
 
 #
 # Read the input files:
@@ -76,6 +78,8 @@
 my $cur_code = 0;
 for(@{$ops->{OPS}}) {
    $_->{CODE}=$cur_code++;
+
+   remember_op($_->full_name(), $_->{CODE});
 }
 
 my $num_ops     = scalar $ops->ops;
@@ -233,6 +237,20 @@
 };
 
 /*
+** Op lookup function:
+*/
+
+static int find_op(const char * name) {
+END_C
+
+#print STDERR "Top level op chars: ", keys %$remembered_ops, "\n";
+
+generate_switch($remembered_ops);
+
+print SOURCE <<END_C;
+}
+
+/*
 ** op lib descriptor:
 */
 
@@ -243,7 +261,8 @@
   $patch_version,
   $num_ops,
   op_info_table,
-  op_func_table
+  op_func_table,
+  find_op
 };
 
 op_lib_t * 
Parrot_DynOp_${base}${suffix}_${major_version}_${minor_version}_${patch_version}(void) 
{
@@ -254,3 +273,70 @@
 
 exit 0;
 
+
+#
+# remember_op()
+#
+
+sub remember_op
+{
+  my ($name, $code) = @_;
+  my $hash = $remembered_ops;
+
+#  print STDERR "Remembering [$code] $name...";
+
+  my @chars = (split(//, $name), "\0");
+
+  while (@chars) {
+    my $char = shift @chars;
+
+#    print "$char...";
+
+    if (@chars) {
+      if (!exists $hash->{$char}) {
+        $hash->{$char} = { };
+      }
+
+      $hash = $hash->{$char}
+    }
+    else {
+      $hash->{$char} = $code;
+#      print "$code.\n";
+    }
+  }
+}
+
+
+#
+# generate_switch()
+#
+
+sub generate_switch {
+  my ($hash, @so_far) = @_;
+  my $index = scalar(@so_far);
+  my $indent = "  " x $index;
+
+  print SOURCE <<END_C;
+${indent}  switch (name[$index]) {
+END_C
+
+  foreach my $key (sort keys %$hash) {
+    print SOURCE "${indent}    case '" . ($key eq "\0" ? "\\0" : $key) . "':\n";
+
+    if (ref $hash->{$key} eq 'HASH') {
+        generate_switch($hash->{$key}, @so_far, $key);
+    }
+    else {
+        print SOURCE "${indent}      return " . $hash->{$key} . ";\n";
+    }
+
+    print SOURCE "${indent}      break;\n"; 
+  }
+
+  print SOURCE <<END_C;
+${indent}    default:
+${indent}      return -1;
+${indent}      break;
+${indent}  }
+END_C
+}
Index: include/parrot/oplib.h
===================================================================
RCS file: /home/perlcvs/parrot/include/parrot/oplib.h,v
retrieving revision 1.3
diff -a -u -r1.3 oplib.h
--- include/parrot/oplib.h      1 Jan 2002 17:22:55 -0000       1.3
+++ include/parrot/oplib.h      1 Feb 2002 13:36:36 -0000
@@ -29,6 +29,7 @@
     INTVAL      op_count;
     op_info_t * op_info_table;
     void *      op_func_table;
+    int (*op_code)(const char * name);
 } op_lib_t;
 
 typedef op_lib_t * (*oplib_init_f)(void);

Reply via email to