Skip to content
Browse files

Support multiple object directories

It is now possible to have a per-user object cache and still share
precompilations of the setting and any other syste-wide installed
modules.
  • Loading branch information...
1 parent e67f09f commit 64f16b59e5e03bf4376db1cebece90270b6a4c30 @sorear committed
Showing with 82 additions and 36 deletions.
  1. +25 −14 lib/CodeGen.cs
  2. +19 −7 lib/CompilerBinding.cs
  3. +6 −5 lib/Kernel.cs
  4. +26 −4 lib/Serialize.cs
  5. +2 −2 src/NieczaBackendDotnet.pm6
  6. +4 −4 src/niecza
View
39 lib/CodeGen.cs
@@ -3637,7 +3637,7 @@ public class DowncallReceiver : CallReceiver {
Kernel.TraceCount = Kernel.TraceFreq = 1;
}
var c = (Compartment)Handle.Unbox(args[1]);
- c.obj_dir = (string)args[2];
+ c.obj_dirs = (args[2] is string) ? new [] { (string)args[2] } : (string[]) args[2];
c.upcall_receiver = (System.Collections.IDictionary)args[3];
return null;
}
@@ -3690,24 +3690,35 @@ public class DowncallReceiver : CallReceiver {
string sub = Kernel.UnboxAny<string>(Builtins.eval_perl5(code).Fetch());
return sub;
}
- public static object unit_need_unit(object[] args) {
- // LinkUnit state is owned by the root
- RuntimeUnit ru = (RuntimeUnit)Handle.Unbox(args[1]);
- string oname = (string)args[2];
-
- RuntimeUnit tg;
+ static RuntimeUnit ProbeLoad(Compartment setting, string oname) {
try {
- tg = (RuntimeUnit) ru.setting.reg.LoadUnit(oname).root;
+ return (RuntimeUnit) setting.reg.LoadUnit(oname).root;
} catch (Exception ex) {
if (Config.SerFailInfo)
Console.WriteLine("Thaw {0} failed: >>>{1}<<<", oname, ex);
- // assume stale at first
- object r1 = Builtins.UpCall(ru.setting, new object[] {
- "compile_unit", oname });
- if (r1 != null)
- return r1;
- tg = (RuntimeUnit) ru.setting.reg.LoadUnit(oname).root;
}
+
+ // if we're here, the load failed
+ // maybe a stale local cache file?
+ if (setting.reg.DeleteTopUnit(oname)) {
+ try {
+ return (RuntimeUnit) setting.reg.LoadUnit(oname).root;
+ } catch (Exception) { }
+ }
+
+ // ok, recompilation is needed I guess
+ object r1 = Builtins.UpCall(setting, new object[] {
+ "compile_unit", oname });
+ if (r1 != null)
+ throw (Exception)r1;
+ return (RuntimeUnit) setting.reg.LoadUnit(oname).root;
+ }
+ public static object unit_need_unit(object[] args) {
+ // LinkUnit state is owned by the root
+ RuntimeUnit ru = (RuntimeUnit)Handle.Unbox(args[1]);
+ string oname = (string)args[2];
+
+ RuntimeUnit tg = ProbeLoad(ru.setting, oname);
string err = ru.owner.LinkUnit(tg);
return err == null ? (object)new Handle(tg) : new Exception(err);
}
View
26 lib/CompilerBinding.cs
@@ -49,7 +49,7 @@ class Downcaller {
internal static Variable upcall_cb;
internal static IDictionary responder;
internal static P6any UnitP, StaticSubP, TypeP, ParamP, ValueP;
- internal static string obj_dir;
+ internal static string[] obj_dirs;
public static object RawDowncall(params object[] args) {
return responder[args];
@@ -173,19 +173,31 @@ public partial class Builtins {
Downcaller.ParamP = param.Fetch();
Downcaller.ValueP = value.Fetch();
- Downcaller.obj_dir = Path.GetFullPath(cmd_obj_dir.IsDefined() ?
- cmd_obj_dir.mo.mro_raw_Str.Get(cmd_obj_dir) :
- Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
- "NieczaModuleCache"));
+ string[] obj_dirs =
+ !cmd_obj_dir.IsDefined() ? new string[0] :
+ cmd_obj_dir.Isa(cmd_obj_dir.mo.setting.StrMO) ?
+ new string[] { cmd_obj_dir.mo.mro_raw_Str.Get(cmd_obj_dir) } :
+ Builtins.UnboxLoS(Kernel.NewRWListVar(cmd_obj_dir)) ;
- Directory.CreateDirectory(Downcaller.obj_dir); // like mkdir -p
+ if (obj_dirs.Length == 0) {
+ obj_dirs = new string[2];
+ obj_dirs[0] = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.Combine("..", "obj"));
+ obj_dirs[1] = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "NieczaModuleCache");
+ }
+
+ for (int i = 0; i < obj_dirs.Length; i++) {
+ Directory.CreateDirectory(obj_dirs[i]); // mkdir -p
+ obj_dirs[i] = Path.GetFullPath(obj_dirs[i]);
+ }
+
+ Downcaller.obj_dirs = obj_dirs;
Downcaller.upcall_cb = cb;
Downcaller.responder = (IDictionary) new Niecza.CLRBackend.DowncallReceiver();
}
public static void cb_init_compartment(Variable c) {
- Downcaller.RawDowncall("set_binding", Downcaller.DCArg(c), Downcaller.obj_dir, new UpcallReceiver());
+ Downcaller.RawDowncall("set_binding", Downcaller.DCArg(c), Downcaller.obj_dirs, new UpcallReceiver());
}
public static Variable cb_prune_match(Variable vr) {
View
11 lib/Kernel.cs
@@ -434,7 +434,7 @@ sealed class EmitUnit {
new AssemblyName(asm_name),
(dll_name == null ? AssemblyBuilderAccess.Run :
AssemblyBuilderAccess.RunAndSave),
- s.obj_dir);
+ s.obj_dirs[ s.obj_dirs.Length - 1 ]);
mod_builder = dll_name == null ?
asm_builder.DefineDynamicModule(asm_name) :
@@ -1026,7 +1026,8 @@ public sealed class RuntimeUnit : IFreeze {
tb.ObjRef();
}
} else {
- Assembly assembly = Assembly.LoadFrom(Path.Combine(tb.setting.obj_dir, n.dll_name));
+ Assembly assembly = Assembly.LoadFrom(Path.Combine(
+ Path.GetDirectoryName(tb.file), n.dll_name));
n.type = tb.type = assembly.GetType(n.asm_name, true);
n.constTable = (Constants)Activator.CreateInstance(n.type);
n.constTable.setting = tb.setting;
@@ -4569,7 +4570,7 @@ public class Compartment {
[CORESaved] public BoxObject<int> FalseV;
internal ObjectRegistry reg;
- public string obj_dir = AppDomain.CurrentDomain.BaseDirectory;
+ public string[] obj_dirs = new string[] { AppDomain.CurrentDomain.BaseDirectory };
internal System.Collections.IDictionary upcall_receiver;
// SubInfo objects can be mutated at runtime by .wrap so they
@@ -6773,14 +6774,14 @@ class LastFrameNode {
string newname = args[3];
// don't try to load the assemblies (we probably can't)
- comp.obj_dir = fromdir;
+ comp.obj_dirs = new [] { fromdir };
Backend.cross_level_load = true;
RuntimeUnit root = (RuntimeUnit)
comp.reg.LoadUnit("MAIN").root;
// reset for writing
- comp.obj_dir = todir;
+ comp.obj_dirs = new [] { todir };
RewriteUnits(root, root, new HashSet<RuntimeUnit>());
View
30 lib/Serialize.cs
@@ -132,6 +132,17 @@ struct ObjRef {
byref[items[or.id]] = or;
}
+ public bool DeleteTopUnit(string name) {
+ string path = Path.Combine(setting.obj_dirs[ setting.obj_dirs.Length - 1 ],
+ name.Replace("::",".") + ".ser");
+ if (File.Exists(path)) {
+ File.Delete(path);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
// Loads a single unit from the compiled-data directory.
// Will throw a ThawException if a stale reference is encountered
// or other data format error.
@@ -151,15 +162,25 @@ struct ObjRef {
return units[name];
}
- string file = Path.Combine(setting.obj_dir,
- name.Replace("::",".") + ".ser");
- byte[] bytes = File.ReadAllBytes(file);
+ // Probe for the topmost cache that contains our module
+ string file = null;
+ byte[] bytes = null;
+ for (int i = setting.obj_dirs.Length - 1; i >= 0; i--) {
+ file = Path.Combine(setting.obj_dirs[i], name.Replace("::",".") + ".ser");
+ if (File.Exists(file)) {
+ bytes = File.ReadAllBytes(file);
+ break;
+ }
+ }
+ if (bytes == null)
+ throw new ThawException("unit not found: " + name);
su = new SerUnit();
su.name = name;
su.hash = NewHash().ComputeHash(bytes);
ThawBuffer tb = new ThawBuffer(setting, this, su, bytes);
+ tb.file = file;
units[name] = su;
bool success = false;
@@ -203,7 +224,7 @@ struct ObjRef {
throw new InvalidOperationException("unit " +name+ " exists");
bool success = false;
- string file = Path.Combine(setting.obj_dir,
+ string file = Path.Combine(setting.obj_dirs[ setting.obj_dirs.Length - 1],
name.Replace("::",".") + ".ser");
FreezeBuffer fb = new FreezeBuffer(this, su);
@@ -565,6 +586,7 @@ class ThawBuffer {
List<object> revalidate = new List<object>();
public Type type;
+ public string file;
internal ThawBuffer(Compartment setting, ObjectRegistry reg, SerUnit unit, byte[] data) {
this.data = data;
View
4 src/NieczaBackendDotnet.pm6
@@ -3,7 +3,7 @@ our $PassSimplifier;
class NieczaBackendDotnet;
has $.safemode = False;
-has $.obj_dir;
+has @.obj_dirs;
has $.run_args = [];
enum Phaser < INIT END UNIT_INIT KEEP UNDO LEAVE ENTER PRE POST CATCH CONTROL CHECK >;
@@ -65,7 +65,7 @@ class Value { ... }
method new(*%_) {
my $self = callsame;
- Q:CgOp { (rnull (cb_init_slave {&upcalled} (@ {$self.obj_dir}) {Unit} {StaticSub} {Type} {Param} {Value})) };
+ Q:CgOp { (rnull (cb_init_slave {&upcalled} (@ {$self.obj_dirs}) {Unit} {StaticSub} {Type} {Param} {Value})) };
downcall("safemode") if $self.safemode;
$self;
}
View
8 src/niecza
@@ -53,7 +53,7 @@ our $Actions; $Actions = $Actions but role {
}
my $usage = q:to/EOM/;
-niecza -- a command line wrapper for Niecza
+niecza -- a Perl 6 compiler
usage: niecza -e 'code' # run a one-liner
OR: niecza file.pl [args] # run a program
@@ -83,7 +83,7 @@ my @lib = $basedir.append("lib"), ".".IO.realpath;
my $lang = "CORE";
my $safe = False;
my $bcnd = "dotnet";
-my $odir = Str; # backend auto-detect
+my @odir; # backend auto-detect
my $verb = 0;
my @eval;
my $cmod = False;
@@ -103,14 +103,14 @@ GetOptions(:!permute,
"compile|c" => sub { $comp = True },
"safe" => sub { $safe = True },
"include|I=s" => sub { unshift @lib, $_.IO.realpath },
- "obj-dir=s" => sub { $odir = $_ },
+ "obj-dir=s" => sub { push @odir, $_ },
"help|h" => sub { say $usage; exit 0 },
"no-include-source" => sub { $*no_incl_source = True },
);
my @*INC;
if $bcnd eq 'dotnet' || $bcnd eq 'mono' {
- $Backend = NieczaBackendDotnet.new(obj_dir => $odir, safemode => $safe);
+ $Backend = NieczaBackendDotnet.new(obj_dirs => @odir, safemode => $safe);
}
else {
note "Backend '$bcnd' not supported";

0 comments on commit 64f16b5

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