class NullString {
static Void main() {
NullString().go
}
Void go() {
a := Foo().start
b := Foo().start
c := Foo().start
a.join
b.join
c.join
}
}
const class Foo : Thread {
new make() : super.make(){}
override Obj run(){
locals.set("value", 0)
return this
}
}
result in:
sys::NullErr: key is null
at fan.sys.NullErr.<init>(NullErr.java:45)
at fan.sys.NullErr.make(NullErr.java:31)
at fan.sys.NullErr.make(NullErr.java:28)
at fan.sys.NullErr.make(NullErr.java:21)
at fan.sys.Map.set(Map.java:114)
at fan.NullString_0.Foo.run(/C:/stuff/fan/NullString.fan:21)
at fan.sys.Thread$Val.run(Thread.java:453)
Chris - you're the man when it comes to finding bugs.
That bug is actually a race condition in the Java class loading where we emit from fcode to bytecode. I've fixed for the next build.
I don't have a unified diff handy, but if you want to fix yourself it is in jfan/fan/sys/FanClassLoader.java, add this to line 127:
e.printStackTrace();
}
}
// ensure pod is emitted with our constant pool before
// loading any classes inside of it (if this was the
// actual class to load, then we are done)
pod.emit();
if (typeName.equals("$Pod")) return pod.emit();
// if the type name ends with $ then this is a mixin body
// class being used before we have loaded the mixin interface,
// so load them both, then we should it registered by name;
cgrinds Thu 28 Aug 2008
I'm confused. Why does this program:
class NullString { static Void main() { NullString().go } Void go() { a := Foo().start b := Foo().start c := Foo().start a.join b.join c.join } } const class Foo : Thread { new make() : super.make(){} override Obj run(){ locals.set("value", 0) return this } }result in:
sys::NullErr: key is null at fan.sys.NullErr.<init>(NullErr.java:45) at fan.sys.NullErr.make(NullErr.java:31) at fan.sys.NullErr.make(NullErr.java:28) at fan.sys.NullErr.make(NullErr.java:21) at fan.sys.Map.set(Map.java:114) at fan.NullString_0.Foo.run(/C:/stuff/fan/NullString.fan:21) at fan.sys.Thread$Val.run(Thread.java:453)The fcode looks fine:
--concurrency_examples::Foo : sys::Thread-- [SourceFile] size=16 NullString.fan [LineNumber] size=2 15 make () -> sys::Void [ctor public] [Code] 0: LoadVar 0 3: CallCtor sys::Thread.make() -> sys::Void 6: ReturnVoid [LineNumber] size=2 16 run () -> sys::Obj [override public virtual] [Code] 0: CallStatic sys::Thread.locals() -> [sys::Str:sys::Obj] 3: LoadStr value 6: LoadInt 0 9: CallVirtual sys::Map.set(sys::Obj, sys::Obj) -> sys::Map 12: Pop 13: LoadVar 0 16: ReturnObj [LineNumber] size=2 17brian Thu 28 Aug 2008
Chris - you're the man when it comes to finding bugs.
That bug is actually a race condition in the Java class loading where we emit from fcode to bytecode. I've fixed for the next build.
I don't have a unified diff handy, but if you want to fix yourself it is in jfan/fan/sys/FanClassLoader.java, add this to line 127:
e.printStackTrace(); } } // ensure pod is emitted with our constant pool before // loading any classes inside of it (if this was the // actual class to load, then we are done) pod.emit(); if (typeName.equals("$Pod")) return pod.emit(); // if the type name ends with $ then this is a mixin body // class being used before we have loaded the mixin interface, // so load them both, then we should it registered by name;cgrinds Thu 28 Aug 2008
Thanks Brian, that fixes the bug for me.