Skip to content
Browse files

Move MRO calculation to compile time

  • Loading branch information...
1 parent 53a549d commit 6dbac00bd4b7f7e4e705eb3933fb9c55ca52f5ba @sorear committed Oct 6, 2010
Showing with 67 additions and 107 deletions.
  1. +17 −95 lib/Kernel.cs
  2. +1 −3 src/CLRTypes.pm
  3. +16 −8 src/CSharpBackend.pm
  4. +33 −1 src/Metamodel.pm
View
112 lib/Kernel.cs
@@ -448,6 +448,9 @@ public List<DynMetaObject> superclasses
k.subclasses.Add(wr_this);
}
mro = arr;
+ isa.Clear();
+ foreach (DynMetaObject k in arr)
+ isa.Add(k);
}
~DynMetaObject() {
@@ -502,21 +505,6 @@ public List<DynMetaObject> superclasses
return isa.Contains(m);
}
- private static bool C3Debug =
- Environment.GetEnvironmentVariable("NIECZA_C3_TRACE") != null;
-
- private static string MROStr(List<DynMetaObject> chain) {
- return Kernel.JoinS(" <- ", chain, delegate(DynMetaObject o) {
- return o.name;
- });
- }
-
- private static void DumpC3Lists(string f, DynMetaObject[] m,
- List<List<DynMetaObject>> d) {
- Console.WriteLine(f + MROStr(new List<DynMetaObject>(m)) + " // " +
- Kernel.JoinS(" | ", d, MROStr));
- }
-
public void AddMethod(string name, IP6 code) {
local[name] = code;
Invalidate();
@@ -532,82 +520,21 @@ public List<DynMetaObject> superclasses
return code;
}
- public void AddAttribute(string name) {
- local_attr.Add(name);
- Invalidate();
- }
- public void AddSuperclass(DynMetaObject other) {
- superclasses.Add(other);
+ public void FillProtoClass(string[] attr) {
+ FillClass(attr, attr, new DynMetaObject[] {},
+ new DynMetaObject[] { this });
}
- // this gets called more than once for Scalar, ClassHOW, and Sub
- // just be sure that the attrib list doesn't change
- public void Complete() {
- List<List<DynMetaObject>> toMerge = new List<List<DynMetaObject>>();
- List<DynMetaObject> mro_l = new List<DynMetaObject>();
- isa = new HashSet<DynMetaObject>();
- toMerge.Add(new List<DynMetaObject>());
- toMerge[0].Add(this);
-
- foreach (DynMetaObject dmo in superclasses) {
- toMerge[0].Add(dmo);
- toMerge.Add(new List<DynMetaObject>(dmo.mro));
- }
-
- if (C3Debug)
- DumpC3Lists("C3 start: " + name + ": ", mro, toMerge);
-
- while (true) {
-top:
- if (C3Debug)
- DumpC3Lists("C3 iter: ", mro, toMerge);
-
- foreach (List<DynMetaObject> h in toMerge) {
- if (h.Count == 0) {
- continue; // next CANDIDATE
- }
- DynMetaObject cand = h[0];
- foreach (List<DynMetaObject> bs in toMerge) {
- if (bs.Count == 0) {
- continue; // next BLOCKER
- }
- if (bs[0] == cand) {
- continue;
- }
- if (bs.Contains(cand)) {
- goto blocked;
- }
- }
- // no reason not to immediately put this, and by loop
- // order the C3 condition is kept
- mro_l.Add(cand);
- isa.Add(cand);
- foreach (List<DynMetaObject> l in toMerge) {
- l.Remove(cand);
- }
- goto top;
-blocked:
- ;
- }
- if (C3Debug)
- DumpC3Lists("C3 end: ", mro, toMerge);
- foreach (List<DynMetaObject> l in toMerge) {
- if (l.Count != 0) {
- // should refactor this to use a real p6exception
- throw new Exception("C3 MRO inconsistency detected");
- }
- }
- break;
- }
-
- SetMRO(mro_l.ToArray());
+ public void FillClass(string[] local_attr, string[] all_attr,
+ DynMetaObject[] superclasses, DynMetaObject[] mro) {
+ this.superclasses = new List<DynMetaObject>(superclasses);
+ SetMRO(mro);
+ this.local_attr = new List<string>(local_attr);
nslots = 0;
- foreach (DynMetaObject k in mro) {
- foreach (string an in k.local_attr) {
- slotMap[an] = nslots++;
- }
+ foreach (string an in all_attr) {
+ slotMap[an] = nslots++;
}
Invalidate();
@@ -1015,25 +942,20 @@ class ExitRunloopException : Exception { }
static Kernel() {
DynMetaObject pStrMO = new DynMetaObject("protoStr");
- pStrMO.AddAttribute("value");
- pStrMO.Complete();
+ pStrMO.FillProtoClass(new string[] { "value" });
StrP = new DynObject(pStrMO);
StashMO = new DynMetaObject("Stash");
- StashMO.AddAttribute("value");
- StashMO.Complete();
+ StashMO.FillProtoClass(new string[] { "value" });
StashP = new DynObject(StashMO);
SubMO = new DynMetaObject("Sub");
SubMO.OnInvoke = new DynMetaObject.InvokeHandler(SubInvoke);
- SubMO.AddAttribute("outer");
- SubMO.AddAttribute("info");
- SubMO.Complete();
+ SubMO.FillProtoClass(new string[] { "outer", "info" });
SubMO.AddMethod("INVOKE", MakeSub(SubInvokeSubSI, null));
ScalarMO = new DynMetaObject("Scalar");
- ScalarMO.AddAttribute("value");
- ScalarMO.Complete();
+ ScalarMO.FillProtoClass(new string[] { "value" });
}
public static Dictionary<string, int> usedNames = new Dictionary<string, int>();
View
4 src/CLRTypes.pm
@@ -22,12 +22,10 @@ my %typedata = (
slots => [f => 'Dictionary<string,Object>'] },
DynMetaObject =>
- { Complete => [m => 'Void'],
+ { FillClass => [m => 'Void'],
HasMRO => [m => 'Boolean'],
AddMultiRegex=> [m => 'Void'],
AddMethod => [m => 'Void'],
- AddSuperclass=> [m => 'Void'],
- AddAttribute => [m => 'Void'],
AddPrivateMethod => [m => 'Void'],
GetPrivateMethod => [m => 'IP6'],
typeObject => [f => 'IP6'],
View
24 src/CSharpBackend.pm
@@ -54,6 +54,8 @@ sub run {
local @cgs;
local $classhow;
+ local $Metamodel::unit = $unit;
+
# 0s just set up variables
# 1s set up subs
# 2s set up objects
@@ -190,16 +192,22 @@ sub pkg2 {
} else {
push @thaw, CgOp::rawsset($p, CgOp::rawnew("clr:$cl_ty",
CgOp::clr_string($_->name)));
- for my $a (@{ $_->attributes }) {
- push @thaw, CgOp::rawcall(CgOp::rawsget($p), 'AddAttribute',
- CgOp::clr_string($a));
- }
}
- for my $s (@{ $_->superclasses }) {
- push @thaw, CgOp::rawcall(CgOp::rawsget($p), 'AddSuperclass',
- CgOp::rawsget($unit->deref($s)->{peer}{mo}));
+ my $abase;
+ for (@{ $_->linearized_mro }) {
+ $abase += scalar @{ $unit->deref($_)->attributes };
}
- push @thaw, CgOp::rawcall(CgOp::rawsget($p), 'Complete');
+ push @thaw, CgOp::rawcall(CgOp::rawsget($p), 'FillClass',
+ CgOp::rawnewarr('str', map { CgOp::clr_string($_) }
+ @{ $_->attributes }),
+ CgOp::rawnewarr('str', map { CgOp::clr_string($_) }
+ map { @{ $unit->deref($_)->attributes } } @{ $_->linearized_mro }),
+ CgOp::rawnewarr('clr:DynMetaObject',
+ map { CgOp::rawsget($unit->deref($_)->{peer}{mo}) }
+ @{ $_->superclasses }),
+ CgOp::rawnewarr('clr:DynMetaObject',
+ map { CgOp::rawsget($unit->deref($_)->{peer}{mo}) }
+ @{ $_->linearized_mro }));
push @thaw, CgOp::rawsset($wh6, CgOp::rawnew('clr:DynObject', CgOp::rawsget($p)));
push @thaw, CgOp::setfield('slots', CgOp::cast('clr:DynObject', CgOp::rawsget($wh6)), CgOp::null('clr:object[]'));
push @thaw, CgOp::setfield('typeObject', CgOp::rawsget($p), CgOp::rawsget($wh6));
View
34 src/Metamodel.pm
@@ -137,6 +137,7 @@ our $unit;
default => sub { [] });
has multi_regex_lists => (isa => 'HashRef[ArrayRef]',
is => 'ro', lazy => 1, default => sub { +{} });
+ has linearized_mro => (isa => 'ArrayRef[ArrayRef]', is => 'rw');
sub add_attribute {
my ($self, $name) = @_;
@@ -167,6 +168,35 @@ our $unit;
$self->add_super($unit->get_stash_obj(
@{ $opensubs[-1]->find_pkg($self->_defsuper) }));
}
+
+ my @merge;
+ push @merge, [ $unit->make_ref($self), @{ $self->superclasses } ];
+ for (@{ $self->superclasses }) {
+ push @merge, [ @{ $unit->deref($_)->linearized_mro } ];
+ }
+ my @mro;
+ my %used;
+
+ MRO: for(;;) {
+ CANDIDATE: for (my $i = 0; $i < @merge; $i++) {
+ my $item = $merge[$i][0];
+ for (my $j = 0; $j < @merge; $j++) {
+ for (my $k = 1; $k < @{ $merge[$j] }; $k++) {
+ next CANDIDATE if $unit->deref($merge[$j][$k])
+ == $unit->deref($item);
+ }
+ }
+ shift @{ $merge[$i] };
+ splice @merge, $i, 1 if !@{ $merge[$i] };
+ push @mro, $item unless $used{$unit->deref($item)}++;
+ next MRO;
+ }
+ last MRO if (!@merge);
+ die "C3-MRO wedged! " . join(" | ", map { (join " <- ",
+ map { $unit->deref($_)->name } @$_) } @merge);
+ }
+
+ $self->linearized_mro(\@mro);
}
sub _defsuper { 'Any' } #XXX CORE::Any
@@ -513,6 +543,7 @@ our $unit;
sub make_ref {
my ($self, $thing) = @_;
my $xid;
+ Carp::confess "trying to make_ref null" unless $thing;
if (!defined ($xid = $thing->xid)) {
$thing->xid($xid = scalar @{ $self->xref });
push @{ $self->xref }, $thing;
@@ -523,7 +554,8 @@ our $unit;
sub deref {
my ($self, $thing) = @_;
Carp::confess "trying to dereference null" unless $thing;
- return $self->get_unit($thing->[0])->xref->[$thing->[1]];
+ return $self->get_unit($thing->[0])->xref->[$thing->[1]] //
+ Carp::confess "invalid ref @$thing";
}
sub visit_units_preorder {

0 comments on commit 6dbac00

Please sign in to comment.
Something went wrong with that request. Please try again.