Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Pickle.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // File: Pickle.C
00020 
00021 #include "Pickle.H"
00022 #include "Parser.H"
00023 #include "Expr.H"
00024 #include "Val.H"
00025 #include "Err.H"
00026 #include "Files.H"
00027 #include "WordKey.H"
00028 #include "ThreadData.H"
00029 #include <VDirSurrogate.H>
00030 #include <FP.H>
00031 #include <Atom.H>
00032 #include <BufStream.H>
00033 
00034 using std::ios;
00035 using std::streampos;
00036 using std::ostringstream;
00037 using std::cerr;
00038 using std::endl;
00039 using Basics::BufStream;
00040 
00041 class PickleC {
00042 public:
00043   // Consturctor for pickling
00044   PickleC()
00045     : size(0), shortId(NullShortId), linePos(0), read_size(0)
00046     { bytes = NEW(BufStream); }
00047 
00048   // Constructor for unpickling
00049   PickleC(char* str, int sz, const PrefixTbl& prefix, const Context& c)
00050     : size(sz), con(c), shortId(NullShortId), linePos(0), prefix(prefix),
00051       read_size(0)
00052       {
00053         bytes = NEW_CONSTR(BufStream, (str, sz, sz));
00054       }
00055 
00056   void PickleInt8(Basics::int8 n);
00057   void UnpickleInt8(Basics::int8& n);
00058 
00059   void PickleInt16(Basics::uint16 n);
00060   void UnpickleInt16(Basics::uint16& n);
00061 
00062   void PickleInt32(Basics::uint32 n);
00063   void UnpickleInt32(Basics::uint32& n);
00064 
00065   inline void PickleInt(int n) { PickleInt32(n); }
00066   inline void UnpickleInt(int& n)
00067   {
00068     Basics::uint32 un;
00069     UnpickleInt32(un);
00070     n = (int) un;
00071   }
00072 
00073   void PickleInt64(Basics::uint64 n);
00074   void UnpickleInt64(Basics::uint64& n);
00075 
00076   void PickleText(const Text& t);
00077   void UnpickleText(Text& t);
00078   // Same as UnpickleText, but fill an Atom instead.
00079   void UnpickleAtom(Atom& t);
00080 
00081   // Same as PickleText/UnpickleText, but uses a 32-bit integer for
00082   // the length.
00083   void PickleLText(const Text& t);
00084   void UnpickleLText(Text& t);
00085 
00086   // Pickle booleans in a dependable size, because sizeof(bool) can
00087   // change from compiler to compiler.  (The GNU compiler on Alpha
00088   // Linux has sizeof(bool) = 8, most others have sizeof(bool) = 1.)
00089   inline void PickleBool(bool v) { PickleInt8(v ? 1 : 0); }
00090   inline void UnpickleBool(bool& v)
00091   {
00092     Basics::int8 wv;
00093     UnpickleInt8(wv);
00094     v = (wv != 0);
00095   }
00096 
00097   void PickleLongId(const LongId &lid);
00098   void UnpicklLongId(LongId &lid);
00099 
00100   bool PickleVal(bool cut, Val value);
00101   bool UnpickleVal(bool cut, /*OUT*/ Val& value);
00102   Derived::IndicesApp dis;
00103   PrefixTbl prefix;
00104 
00105   // These are intended to be used after pickling a value.
00106   inline const char *getBytes()
00107   {
00108     return bytes->str();
00109   }
00110   inline int getSize()
00111   {
00112     unsigned int result = bytes->tellp();
00113     assert(size == result);
00114     return result;
00115   }
00116 
00117   // This is for use after unpickling.
00118   bool checkNumBytesRead();
00119 private:
00120   BufStream *bytes;
00121   int size, read_size;
00122   Context con;
00123   Text fileName;
00124   ShortId shortId;
00125   int linePos;
00126   TextIntTbl nameTbl;
00127   bool PickleLocation(SrcLoc *loc);
00128   bool UnpickleLocation(SrcLoc*& loc);
00129   bool PickleContext(const Context& c);
00130   bool UnpickleContext(Context& c);
00131   void PickleDepPath(const DepPath& dp);
00132   DepPath UnpickleDepPath();
00133   bool PickleDPS(DPaths *ps);
00134   bool UnpickleDPS(DPaths*& ps);
00135   void CollectDIs(Val value);
00136   bool PickleExpr(Expr expr);
00137   bool UnpickleExpr(Expr& expr);
00138 };
00139 
00140 // Pickle version history:
00141 //
00142 // 2 - All integers pickled in network byte order.  (KCS, 2003-02-05)
00143 
00144 static int currentPickleVersion = 2;
00145 
00146 void PickleC::PickleInt8(Basics::int8 n)
00147 {
00148   FS::Write(*bytes, (char*)&n, sizeof_assert(n, 1));
00149   size += sizeof(n);
00150 }
00151 
00152 void PickleC::PickleInt16(Basics::uint16 n)
00153 {
00154   Basics::uint16 n_net = Basics::hton16(n);
00155   FS::Write(*bytes, (char*)&n_net, sizeof_assert(n_net, 2));
00156   size += sizeof(n_net);
00157 }
00158 
00159 void PickleC::PickleInt32(Basics::uint32 n)
00160 {
00161   Basics::uint32 n_net = Basics::hton32(n);
00162   FS::Write(*bytes, (char*)&n_net, sizeof_assert(n_net, 4));
00163   size += sizeof(n_net);
00164 }
00165 
00166 void PickleC::PickleInt64(Basics::uint64 n)
00167 {
00168   Basics::uint64 n_net = Basics::hton64(n);
00169   FS::Write(*bytes, (char*)&n_net, sizeof_assert(n_net, 8));
00170   size += sizeof(n_net);
00171 }
00172 
00173 void PickleC::UnpickleInt8(Basics::int8& n)
00174 {
00175   FS::Read(*bytes, (char*)&n, sizeof_assert(n, 1));
00176   read_size += sizeof(n);
00177 }
00178 
00179 void PickleC::UnpickleInt16(Basics::uint16& n)
00180 {
00181   Basics::uint16 n_net;
00182   FS::Read(*bytes, (char*)&n_net, sizeof_assert(n_net, 2));
00183   n = Basics::ntoh16(n_net);
00184   read_size += sizeof(n_net);
00185 }
00186 
00187 void PickleC::UnpickleInt32(Basics::uint32& n)
00188 {
00189   Basics::uint32 n_net;
00190   FS::Read(*bytes, (char*)&n_net, sizeof_assert(n_net, 4));
00191   n = Basics::ntoh32(n_net);
00192   read_size += sizeof(n_net);
00193 }
00194 
00195 void PickleC::UnpickleInt64(Basics::uint64& n)
00196 {
00197   Basics::uint64 n_net;
00198   FS::Read(*bytes, (char*)&n_net, sizeof_assert(n_net, 8));
00199   n = Basics::ntoh64(n_net);
00200   read_size += sizeof(n_net);
00201 }
00202 
00203 void PickleC::PickleText(const Text& t)
00204 {
00205   Basics::uint16 len = t.Length();
00206   assert(len == t.Length());
00207   PickleInt16(len);
00208   FS::Write(*bytes, t.chars(), len);
00209   size += len;
00210 }
00211 
00212 void PickleC::UnpickleText(Text& t)
00213 {
00214   Basics::uint16 len;
00215   UnpickleInt16(len);
00216   if (len > size)
00217     throw FS::EndOfFile();
00218   char *s = NEW_PTRFREE_ARRAY(char, len+1);
00219   FS::Read(*bytes, s, len);
00220   read_size += len;
00221   s[len] = 0;
00222   t = Text(s, (void*)s);
00223 }
00224 
00225 void PickleC::UnpickleAtom(Atom& a)
00226 {
00227   Basics::uint16 len;
00228   UnpickleInt16(len);
00229   if (len > size)
00230     throw FS::EndOfFile();
00231   char *s = NEW_PTRFREE_ARRAY(char, len+1);
00232   FS::Read(*bytes, s, len);
00233   read_size += len;
00234   s[len] = 0;
00235   a = Atom(s, (void*)s);
00236 }
00237 
00238 void PickleC::PickleLText(const Text& t)
00239 {
00240   Basics::uint32 len = t.Length();
00241   assert(len == t.Length());
00242   PickleInt32(len);
00243   FS::Write(*bytes, t.chars(), len);
00244   size += len;
00245 }
00246 
00247 void PickleC::UnpickleLText(Text& t)
00248 {
00249   Basics::uint32 len;
00250   UnpickleInt32(len);
00251   if (len > size)
00252     throw FS::EndOfFile();
00253   char *s = NEW_PTRFREE_ARRAY(char, len+1);
00254   FS::Read(*bytes, s, len);
00255   read_size += len;
00256   s[len] = 0;
00257   t = Text(s, (void*)s);
00258 }
00259 
00260 void PickleC::PickleLongId(const LongId &lid)
00261 {
00262   FS::Write(*bytes, (char*)lid.value.byte, sizeof_assert(lid.value.byte, 32));
00263   size += sizeof(lid.value.byte);
00264 }
00265 
00266 void PickleC::UnpicklLongId(LongId &lid)
00267 {
00268   FS::Read(*bytes, (char*)lid.value.byte, sizeof_assert(lid.value.byte, 32));
00269   read_size += sizeof(lid.value.byte);
00270 }
00271 
00272 bool PickleC::PickleLocation(SrcLoc *loc) {
00273   // file name and sid are recorded only once, at the start of pickling
00274   // the expression of a closure.
00275   // pickle loc->line and loc->character:
00276   char lineDelta = (char)(loc->line - linePos);
00277   char charPos = (char)loc->character;
00278   PickleInt8(lineDelta);
00279   PickleInt8(charPos);
00280   // update the location:
00281   linePos = loc->line;
00282   return true;
00283 }
00284 
00285 bool PickleC::UnpickleLocation(SrcLoc*& loc) {
00286   // unpickle loc->line:
00287   char lineDelta;
00288   UnpickleInt8(lineDelta);
00289   linePos += (int)lineDelta;
00290   // unpickle loc->character:
00291   char charPos;
00292   UnpickleInt8(charPos);
00293 
00294   loc = NEW_CONSTR(SrcLoc, (linePos, (int)charPos, fileName, shortId));
00295   return true;
00296 }
00297 
00298 bool PickleC::PickleContext(const Context& c) {
00299   bool success = true;
00300   Context cc = c;
00301   Basics::uint16 len = cc.Length();
00302   // Check for overflow of length integer
00303   assert(len == cc.Length());
00304   PickleInt16(len);
00305   unsigned int pickled_entry_count = 0;
00306   while (success && !cc.Null()) {
00307     Assoc elem = cc.Pop();
00308     PickleText(elem->name);
00309     success = PickleVal(true, elem->val);
00310     pickled_entry_count++;
00311   }
00312   // Make sure we pickled the number we said we would
00313   assert(len == pickled_entry_count);
00314   return success;
00315 }
00316 
00317 bool PickleC::UnpickleContext(Context& c) {
00318   bool success = true;
00319   Basics::uint16 cLen;
00320   UnpickleInt16(cLen);
00321   Val val;
00322   while (success && cLen--) {
00323     Atom name;
00324     UnpickleAtom(name);
00325     success = UnpickleVal(true, val);
00326     c.Append1D(NEW_CONSTR(AssocVC, (name, val)));
00327   }
00328   return success;
00329 }
00330 
00331 void PickleC::PickleDepPath(const DepPath& dp) {
00332   // prefix encoding:
00333   Basics::uint16 index = prefix.Put(*dp.content->path, nameTbl);
00334   // path kind:
00335   char pk = (char)dp.content->pKind;
00336   PickleInt8(pk);
00337   // prefix index:
00338   PickleInt16(index);
00339 }
00340 
00341 DepPath PickleC::UnpickleDepPath() {
00342   // path kind:
00343   char pk;
00344   UnpickleInt8(pk);
00345   // arcs:
00346   Basics::uint16 index;
00347   UnpickleInt16(index);
00348   ArcSeq *path = prefix.Get(index);
00349   // fingerprint: pathFP is not in the pickle.
00350   return DepPath(path, (PathKind)pk);
00351 }
00352 
00353 bool PickleC::PickleDPS(DPaths *ps) {
00354   Basics::uint16 len = 0;
00355   if (ps != NULL) {
00356     len = ps->Size();
00357     // Check for length overflow
00358     assert(len == ps->Size());
00359   }
00360   PickleInt16(len);
00361 
00362   unsigned int pickled_path_count = 0;
00363   if (ps != NULL) {
00364     DepPathTbl::TIter iter(ps);  
00365     DepPathTbl::KVPairPtr ptr;
00366     while (iter.Next(ptr))
00367       {
00368         PickleDepPath(ptr->key);
00369         pickled_path_count++;
00370       }
00371   }
00372   // Make sure we pickled the number we said we would
00373   assert(pickled_path_count == len);
00374   return true;
00375 }
00376 
00377 bool PickleC::UnpickleDPS(DPaths*& ps) {
00378   Basics::uint16 len;
00379   UnpickleInt16(len);
00380   
00381   if (len > 0) {
00382     ps = NEW_CONSTR(DPaths, (len));
00383     while (len-- > 0) {
00384       DepPath newPath(UnpickleDepPath());
00385       DepPathTbl::KVPairPtr dummyPtr;
00386       Val val = LookupPath(&newPath, this->con);
00387       ps->Put(newPath, val, dummyPtr);
00388     }
00389   }
00390   return true;
00391 }
00392 
00393 void PickleC::CollectDIs(Val value) {
00394   /* Collect all the deriveds in the value. */
00395   switch (value->vKind) {
00396   case ListVK:
00397     {
00398       Vals elems = ((ListVC*)value)->elems;
00399       while (!elems.Null())
00400         CollectDIs(elems.Pop());
00401       break;
00402     }
00403   case BindingVK:
00404     {
00405       Context elems = ((BindingVC*)value)->elems;
00406       while (!elems.Null())
00407         CollectDIs(elems.Pop()->val);
00408       break;
00409     }
00410   case TextVK:
00411     {
00412       TextVC *tv = (TextVC*)value;
00413       if (!tv->HasTxt()) dis.Append(tv->Sid());
00414       break;
00415     }
00416   case ClosureVK:
00417     {
00418       ClosureVC *cl = (ClosureVC*)value;
00419       Text name(cl->func->name);
00420       Context work = cl->con;
00421       while (!work.Null()) {
00422         Assoc a = work.Pop();
00423         if (a->name != name) CollectDIs(a->val);
00424       }
00425       break;
00426     }
00427   case ModelVK:
00428     {
00429       dis.Append(((ModelVC*)value)->content->mRoot->shortId());
00430       break;
00431     }
00432   default:
00433     break;
00434   }
00435   return;
00436 }
00437 
00438 bool PickleC::PickleExpr(Expr expr) {
00439   PickleLocation(expr->loc);
00440 
00441   char ek = (char)expr->kind;
00442   PickleInt8(ek);
00443   switch (ek) {
00444   case ConstantEK:
00445     {
00446       PickleVal(true, ((ConstantEC*)expr)->val);
00447       break;
00448     }
00449   case IfEK:
00450     {
00451       IfEC *ife = (IfEC*)expr;
00452       PickleExpr(ife->test);
00453       PickleExpr(ife->then);
00454       PickleExpr(ife->els);
00455       break;
00456     }
00457   case ComputedEK:
00458     {
00459       PickleExpr(((ComputedEC*)expr)->name);
00460       break;
00461     }
00462   case ExprListEK:
00463     {
00464       Exprs es = ((ExprListEC*)expr)->elems;
00465       Basics::uint16 len = es.size();
00466       // Check for overflow of length integer
00467       assert(len == es.size());
00468       PickleInt16(len);
00469       for (int i = 0; i < len; i++) {
00470         PickleExpr(es.get(i));
00471       }
00472       break;
00473     }
00474   case ArgListEK:
00475     {
00476       Exprs es = ((ArgListEC*)expr)->elems;
00477       PickleInt64(((ArgListEC*)expr)->inPKs);
00478       Basics::uint16 len = es.size();
00479       // Check for overflow of length integer
00480       assert(len == es.size());
00481       PickleInt16(len);
00482       for (int i = 0; i < len; i++) {
00483         PickleExpr(es.get(i));
00484       }
00485       break;
00486     }
00487   case StmtListEK:
00488     {
00489       Exprs es = ((StmtListEC*)expr)->elems;
00490       Basics::uint16 len = es.size();
00491       // Check for overflow of length integer
00492       assert(len == es.size());
00493       PickleInt16(len);
00494       for (int i = 0; i < len; i++) {
00495         PickleExpr(es.get(i));
00496       }
00497       break;
00498     }
00499   case ListEK:
00500     {
00501       Exprs es = ((ListEC*)expr)->elems;
00502       Basics::uint16 len = es.size();
00503       // Check for overflow of length integer
00504       assert(len == es.size());
00505       PickleInt16(len);
00506       for (int i = 0; i < len; i++) {
00507         PickleExpr(es.get(i));
00508       }
00509       break;
00510     }
00511   case AssignEK:
00512     {
00513       AssignEC *ae = (AssignEC*)expr;
00514       PickleExpr(ae->lhs);
00515       PickleExpr(ae->rhs);
00516       PickleBool(ae->isFunc);
00517       break;
00518     }
00519   case BindEK:
00520     {
00521       BindEC *be = (BindEC*)expr;
00522       PickleExpr(be->lhs);
00523       PickleExpr(be->rhs);
00524       break;
00525     }
00526   case NameEK:
00527     {
00528       NameEC *ne = (NameEC*)expr;
00529       PickleText(ne->id);
00530       break;
00531     }
00532   case BindingEK:
00533     {
00534       Exprs assocs = ((BindingEC*)expr)->assocs;
00535       Basics::uint16 len = assocs.size();
00536       // Check for overflow of length integer
00537       assert(len == assocs.size());
00538       PickleInt16(len);
00539       for (int i = 0; i < len; i++) {
00540         PickleExpr(assocs.get(i));
00541       }
00542       break;
00543     }
00544   case ApplyOpEK:
00545     {
00546       ApplyOpEC *ae = (ApplyOpEC*)expr;
00547       PickleText(ae->op);
00548       PickleExpr(ae->e1);
00549       PickleExpr(ae->e2);
00550       break;
00551     }
00552   case ApplyUnOpEK:
00553     {
00554       ApplyUnOpEC *ae = (ApplyUnOpEC*)expr;
00555       PickleText(ae->op);
00556       PickleExpr(ae->e);
00557       break;
00558     }
00559   case ModelEK:
00560     {
00561       ModelEC *me = (ModelEC*)expr;
00562       PickleExpr(me->files);
00563       PickleExpr(me->imports);
00564       PickleExpr(me->block);
00565       PickleLongId(me->modelRoot->longid);
00566       break;
00567     }
00568   case FileEK:
00569     {
00570       FileEC *fe = (FileEC*)expr;
00571       // the name:
00572       PickleExpr(fe->name);
00573       // the local path:
00574       PickleText(fe->localPath);
00575       // the model root:
00576       PickleLongId(fe->modelRoot->longid);
00577       // the import flag:
00578       PickleBool(fe->import);
00579       break;
00580     }
00581   case PrimitiveEK:
00582     {
00583       PrimitiveEC *pe = (PrimitiveEC*)expr;
00584       PickleText(pe->name);
00585       break;
00586     }
00587   case PairEK:
00588     {
00589       PairEC *pe = (PairEC*)expr;
00590       PickleExpr(pe->first);
00591       PickleExpr(pe->second);
00592       break;
00593     }
00594   case SelectEK:
00595     {
00596       SelectEC *se = (SelectEC*)expr;
00597       PickleExpr(se->binding);
00598       PickleExpr(se->field);
00599       PickleBool(se->bang);
00600       break;
00601     }
00602   case FuncEK:
00603     {
00604       FuncEC *fe = (FuncEC*)expr;
00605       PickleText(fe->name);
00606       PickleBool(fe->noCache);
00607       PickleExpr(fe->args);
00608       PickleExpr(fe->body);
00609       break;
00610     }
00611   case BlockEK:
00612     {
00613       BlockEC *be = (BlockEC*)expr;
00614       PickleExpr(be->assocs);
00615       PickleExpr(be->body);
00616       PickleBool(be->isReturn);
00617       break;
00618     }
00619   case IterateEK:
00620     {
00621       IterateEC *ie = (IterateEC*)expr;
00622       PickleExpr(ie->control);
00623       PickleExpr(ie->e);
00624       PickleExpr(ie->body);
00625       break;
00626     }
00627   case ApplyEK:
00628     {
00629       ApplyEC *ae = (ApplyEC*)expr;
00630       PickleExpr(ae->func);
00631       PickleExpr(ae->args);
00632       break;
00633     }
00634   case ErrorEK:
00635     break;
00636   default:
00637     throw("Bad expression type in pickling.\n");
00638   }
00639   return true;
00640 }
00641 
00642 bool PickleC::UnpickleExpr(Expr& expr) {
00643   SrcLoc *loc;
00644   UnpickleLocation(loc);
00645 
00646   char ek;
00647   UnpickleInt8(ek);
00648   switch (ek) {
00649   case ConstantEK:
00650     {
00651       Val val;
00652       UnpickleVal(true, val);
00653       expr = NEW_CONSTR(ConstantEC, (val, loc));
00654       break;
00655     }
00656   case IfEK:
00657     {
00658       Expr test, then, els;
00659       UnpickleExpr(test);
00660       UnpickleExpr(then);
00661       UnpickleExpr(els);
00662       expr = NEW_CONSTR(IfEC, (test, then, els, loc));
00663       break;
00664     }
00665   case ComputedEK:
00666     {
00667       Expr name;
00668       UnpickleExpr(name);
00669       expr = NEW_CONSTR(ComputedEC, (name));
00670       break;
00671     }
00672   case ExprListEK:
00673     {
00674       Basics::uint16 len;
00675       UnpickleInt16(len);
00676       ExprListEC *elst = NEW_CONSTR(ExprListEC, (len, loc));
00677       Expr elem;
00678       while (len--) {
00679         UnpickleExpr(elem);
00680         elst->AddExpr(elem);
00681       }
00682       expr = elst;
00683       break;
00684     }
00685   case ArgListEK:
00686     {
00687       Bit64 inPKs;
00688       UnpickleInt64(inPKs);
00689       Basics::uint16 len;
00690       UnpickleInt16(len);
00691       ArgListEC *alst = NEW_CONSTR(ArgListEC, (len, loc));
00692       Expr elem;
00693       while (len--) {
00694         UnpickleExpr(elem);
00695         alst->AddExpr(elem, false);
00696       }
00697       alst->inPKs = inPKs;
00698       expr = alst;
00699       break;
00700     }
00701   case StmtListEK:
00702     {
00703       Basics::uint16 len;
00704       UnpickleInt16(len);
00705       StmtListEC *es = NEW_CONSTR(StmtListEC, (loc));
00706       Expr elem;
00707       while (len--) {
00708         UnpickleExpr(elem);
00709         es->AddExpr(elem);
00710       }
00711       expr = es;
00712       break;
00713     }
00714   case ListEK:
00715     {
00716       Basics::uint16 len;
00717       UnpickleInt16(len);
00718       ListEC *elst = NEW_CONSTR(ListEC, (len, loc));
00719       Expr elem;
00720       while (len--) {
00721         UnpickleExpr(elem);
00722         elst->AddExpr(elem);
00723       }
00724       expr = elst;
00725       break;
00726     }
00727   case AssignEK:
00728     {
00729       Expr lhs, rhs;
00730       UnpickleExpr(lhs);
00731       UnpickleExpr(rhs);
00732       bool isFunc;
00733       UnpickleBool(isFunc);
00734       expr = NEW_CONSTR(AssignEC, ((NameEC*)lhs, rhs, isFunc, loc));
00735       break;
00736     }
00737   case BindEK:
00738     {
00739       Expr lhs, rhs;
00740       UnpickleExpr(lhs);
00741       UnpickleExpr(rhs);
00742       expr = NEW_CONSTR(BindEC, (lhs, rhs, loc));
00743       break;
00744     }
00745   case NameEK:
00746     {
00747       Text id;
00748       UnpickleText(id);
00749       expr = NEW_CONSTR(NameEC, (id, loc));
00750       break;
00751     }
00752   case BindingEK:
00753     {
00754       Basics::uint16 len;
00755       UnpickleInt16(len);
00756       BindingEC *be = NEW_CONSTR(BindingEC, (len, loc));
00757       Expr elem;
00758       while (len--) {
00759         UnpickleExpr(elem);
00760         be->AddExpr(elem);
00761       }
00762       expr = be;
00763       break;
00764     }
00765   case ApplyOpEK:
00766     {
00767       // the operator:
00768       Text op;
00769       UnpickleText(op);
00770       // the operands:
00771       Expr e1, e2;
00772       UnpickleExpr(e1);
00773       UnpickleExpr(e2);
00774       expr = NEW_CONSTR(ApplyOpEC, (e1, op, e2, loc));
00775       break;
00776     }
00777   case ApplyUnOpEK:
00778     {
00779       // the operator:
00780       Text op;
00781       UnpickleText(op);
00782       // the operand:
00783       Expr e;
00784       UnpickleExpr(e);
00785       expr = NEW_CONSTR(ApplyUnOpEC, (op, e, loc));
00786       break;
00787     }
00788   case ModelEK:
00789     {
00790       Expr files, imports, block;
00791       UnpickleExpr(files);
00792       UnpickleExpr(imports);
00793       UnpickleExpr(block);
00794       LongId lid;
00795       UnpicklLongId(lid);
00796       VestaSource *modelRoot = lid.lookup();
00797       expr = NEW_CONSTR(ModelEC, 
00798                         ((ExprListEC*)files, (ExprListEC*)imports, block, 
00799                          modelRoot, loc));
00800       break;
00801     }
00802   case FileEK:
00803     {
00804       Expr name;
00805       UnpickleExpr(name);
00806       Text localPath;
00807       UnpickleText(localPath);
00808       LongId lid;
00809       UnpicklLongId(lid);
00810       VestaSource *modelRoot = lid.lookup();
00811       bool import;
00812       UnpickleBool(import);
00813       expr = NEW_CONSTR(FileEC, 
00814                         ((NameEC*)name, localPath, modelRoot, import, loc));
00815       break;
00816     }
00817   case PrimitiveEK:
00818     {
00819       Text name;
00820       UnpickleText(name);
00821       expr = NEW_CONSTR(PrimitiveEC, (name, LookupPrim(name), loc));
00822       break;
00823     }
00824   case PairEK:
00825     {
00826       Expr first, second;
00827       UnpickleExpr(first);
00828       UnpickleExpr(second);
00829       expr = NEW_CONSTR(PairEC, (first, second, loc));
00830       break;
00831     }
00832   case SelectEK:
00833     {
00834       Expr binding, field;
00835       UnpickleExpr(binding);
00836       UnpickleExpr(field);
00837       bool bang;
00838       UnpickleBool(bang);
00839       expr = NEW_CONSTR(SelectEC, (binding, field, bang, loc));
00840       break;
00841     }
00842   case FuncEK:
00843     {
00844       Text name;
00845       UnpickleText(name);
00846       bool noCache;
00847       UnpickleBool(noCache);
00848       Expr args, body;
00849       UnpickleExpr(args);
00850       UnpickleExpr(body);
00851       expr = NEW_CONSTR(FuncEC, (noCache, name, (ArgListEC*)args, body, loc));
00852       break;
00853     }
00854   case BlockEK:
00855     {
00856       Expr assocs, body;
00857       UnpickleExpr(assocs);
00858       UnpickleExpr(body);
00859       bool isReturn;
00860       UnpickleBool(isReturn);
00861       expr = NEW_CONSTR(BlockEC, ((StmtListEC*)assocs, body, isReturn, loc));
00862       break;
00863     }
00864   case IterateEK:
00865     {
00866       Expr control, e, body;
00867       UnpickleExpr(control);
00868       UnpickleExpr(e);
00869       UnpickleExpr(body);
00870       expr = NEW_CONSTR(IterateEC, (control, e, (StmtListEC*)body, loc));
00871       break;
00872     }
00873   case ApplyEK:
00874     {
00875       Expr func, args;
00876       UnpickleExpr(func);
00877       UnpickleExpr(args);
00878       expr = NEW_CONSTR(ApplyEC, (func, (ArgListEC*)args, loc));
00879       break;
00880     }
00881   case ErrorEK:    
00882     {
00883       expr = NEW_CONSTR(ErrorEC, (loc, false));
00884       break;
00885     }
00886   default:
00887     throw("Bad expression type in unpickling.\n");
00888   }
00889   return true;
00890 }
00891 
00892 bool PickleC::PickleVal(bool cut, Val value) {
00893   if (!value->cacheit) return false;
00894   
00895   bool success = true;
00896   
00897   // Pickle value->path:
00898   bool hasPath = (value->path != NULL);
00899   PickleBool(hasPath);
00900   if (hasPath)
00901     PickleDepPath(*(value->path));
00902   
00903   // Pickle subvalues of the value:
00904   if (hasPath && cut)
00905     CollectDIs(value);
00906   else {
00907     char vk = (char)value->vKind;
00908     PickleInt8(vk);
00909     switch (vk) {
00910     case BooleanVK:
00911       {
00912         PickleBool(((BooleanVC*)value)->b);
00913         break;
00914       }
00915     case IntegerVK:
00916       {
00917         PickleInt(((IntegerVC*)value)->num);
00918         break;
00919       }
00920     case PrimitiveVK:
00921       {
00922         PickleText(((PrimitiveVC*)value)->name);
00923         break;
00924       }
00925     case ListVK:
00926       {
00927         ListVC *lstv = (ListVC*)value;  
00928         Vals elems = lstv->elems;
00929         Basics::uint16 len = elems.Length();
00930         // Check for overflow of length integer
00931         assert(len == elems.Length());
00932         PickleInt16(len);
00933         unsigned int pickled_elem_count = 0;
00934         while (success && !elems.Null())
00935           {
00936             success = PickleVal(cut, elems.Pop());
00937             pickled_elem_count++;
00938           }
00939         // Make sure we pickled the number we said we would
00940         assert(pickled_elem_count == len);
00941         success = success && PickleDPS(lstv->lenDps);
00942         break;
00943       }
00944     case BindingVK:
00945       {
00946         BindingVC *bv = (BindingVC*)value;
00947         Context elems = bv->elems;
00948         Basics::uint16 len = elems.Length();
00949         // Check for overflow of length integer
00950         assert(len == elems.Length());
00951         PickleInt16(len);
00952         unsigned int pickled_elem_count = 0;
00953         while (success && !elems.Null()) {
00954           Assoc a = elems.Pop();
00955           PickleText(a->name);
00956           success = PickleVal(cut, a->val);
00957           pickled_elem_count++;
00958         }
00959         // Make sure we pickled the number we said we would
00960         assert(pickled_elem_count == len);
00961         success = success && PickleDPS(bv->lenDps);
00962         break;
00963       }
00964     case TextVK:
00965       {
00966         TextVC *tv = (TextVC*)value;
00967         // Pickle the value as a text value if it doesn't have an
00968         // underlying shortid or if it's short enough that pickling it
00969         // as a raw string would be shorter than pickling the shortid
00970         // representation.
00971         bool asTxt = !tv->HasSid() ||
00972           (tv->HasTxt() && (tv->Length() < (tv->TName().Length() +
00973                                             sizeof(ShortId) + FP::ByteCnt)));
00974         PickleBool(asTxt);
00975         if (asTxt) {
00976           assert(tv->HasTxt());
00977           PickleLText(tv->NDS());
00978         }
00979         else {
00980           assert(tv->HasSid());
00981           PickleText(tv->TName());
00982           ShortId sid = tv->Sid();
00983           PickleInt32(sid);
00984           // Write fingerprint in network byte order.
00985           tv->FingerPrint().Write(*bytes);
00986           size += FP::ByteCnt;
00987           dis.Append(sid);
00988         }
00989         break;
00990       }
00991     case ClosureVK:
00992       {
00993         ClosureVC *cl = (ClosureVC*)value;
00994 
00995         // Pickle the function body:
00996         SrcLoc *loc = cl->func->loc;
00997         PickleText(loc->file);
00998         PickleInt32(loc->shortId);
00999         linePos = loc->line;
01000         PickleInt(linePos);
01001         success = PickleExpr(cl->func);
01002 
01003         // Pickle context:
01004         if (!success) break;
01005         Text name(cl->func->name);
01006         bool recursive;
01007         Context cc = Snip(cl->con, name, recursive);
01008         success = PickleContext(cc);
01009 
01010         // Pickle name:
01011         if (!success) break;
01012         PickleBool(recursive);
01013         PickleLText(name);
01014         break;
01015       }
01016     case ModelVK:
01017       {
01018         ModelVC *model = (ModelVC*)value;
01019         // Name of the model:
01020         PickleText(model->content->name);
01021 
01022         // Sid of the model:
01023         ShortId sid = model->content->sid;
01024         assert(sid != 0);
01025         PickleInt32(sid);
01026 
01027         // Lid, sid, and fptag for the model root:
01028         // Lid is no longer used.
01029         sid = model->content->mRoot->shortId();
01030         PickleInt32(sid);
01031         model->content->mRoot->fptag.Write(*bytes);
01032         size += FP::ByteCnt;
01033  
01034         // Fingerprint:
01035         dis.Append(sid);   // we add the sid of the parent directory
01036         // Pickle fingerprints in network byte order
01037         model->FingerPrintFile().Write(*bytes);
01038         size += FP::ByteCnt;
01039         model->FingerPrint().Write(*bytes);
01040         size += FP::ByteCnt;
01041         break;
01042       }
01043     case ErrorVK:
01044       break;
01045     default:
01046       {
01047         outputMu.lock();      
01048         Error("Bad value type in pickling.\n");
01049         outputMu.unlock();      
01050         success = false;
01051         break;
01052       }
01053     }
01054   }
01055   // value->dps:
01056   if (success)
01057     success = PickleDPS(value->dps);
01058   return success;
01059 }
01060 
01061 bool PickleC::UnpickleVal(bool cut, /*OUT*/ Val& value) {
01062   bool success = true;
01063   
01064   // Unpickle value->path:
01065   bool hasPath;
01066   UnpickleBool(hasPath);
01067   DepPath *path = NULL;
01068   if (hasPath)
01069     path = NEW_CONSTR(DepPath, (UnpickleDepPath()));
01070 
01071   // Unpickle subvalues of the value:
01072   if (hasPath && cut) {
01073     Val val = LookupPath(path, con);
01074     value = val->Copy(true);
01075   }
01076   else {
01077     char vk;
01078     UnpickleInt8(vk);
01079     switch (vk) {
01080     case BooleanVK:
01081       {
01082         bool b;
01083         UnpickleBool(b);
01084         value = NEW_CONSTR(BooleanVC, (b));
01085         break;
01086       }
01087     case IntegerVK:
01088       {
01089         Basics::int32 n;
01090         UnpickleInt(n);
01091         value = NEW_CONSTR(IntegerVC, (n));
01092         break;
01093       }
01094     case PrimitiveVK:
01095       {
01096         Atom name;
01097         UnpickleAtom(name);
01098         value = NEW_CONSTR(PrimitiveVC, (name, LookupPrim(name)));
01099         break;
01100       }
01101     case ListVK:
01102       {
01103         Basics::uint16 len;
01104         UnpickleInt16(len);
01105         Vals elems;
01106         Val v;
01107         while ((len-- > 0) && UnpickleVal(cut, v))
01108           elems.Append1D(v);
01109         value = NEW_CONSTR(ListVC, (elems));
01110         success = success && UnpickleDPS(((ListVC*)value)->lenDps);
01111         break;
01112       }
01113     case BindingVK:
01114       {
01115         Basics::uint16 len;
01116         UnpickleInt16(len);
01117         Context elems;
01118         Val v;
01119         while (success && len--) {
01120           Atom name;
01121           UnpickleAtom(name);
01122           success = UnpickleVal(cut, v);
01123           elems.Append1D(NEW_CONSTR(AssocVC, (name, v)));
01124         }
01125         value = NEW_CONSTR(BindingVC, (elems));
01126         success = success && UnpickleDPS(((BindingVC*)value)->lenDps);
01127         break;
01128       }
01129     case TextVK:
01130       {
01131         bool hasTxt;
01132         UnpickleBool(hasTxt);
01133         if (hasTxt) {
01134           Text t;
01135           UnpickleLText(t);
01136           value = NEW_CONSTR(TextVC, (t));
01137         }
01138         else {
01139           // Must have sid.
01140           Text name;
01141           UnpickleText(name);
01142           ShortId sid;
01143           UnpickleInt32(sid);
01144           FP::Tag tag;
01145           // Read fingerprint in network byte order.
01146           tag.Read(*bytes);
01147           read_size += FP::ByteCnt;
01148           value = NEW_CONSTR(TextVC, (name, sid, tag));
01149         }
01150         break;
01151       }
01152     case ClosureVK:
01153       {
01154         // Unpickle the function body:
01155         UnpickleText(fileName);
01156         UnpickleInt32(shortId);
01157         UnpickleInt(linePos);
01158         Expr func;
01159         success = UnpickleExpr(func);
01160 
01161         // Unpickle context:
01162         Context c;
01163         if (success)
01164           success = UnpickleContext(c);
01165 
01166         // unpickle name:
01167         Text name;
01168         bool recursive;
01169         if (success) {
01170           UnpickleBool(recursive);
01171           UnpickleLText(name);
01172         }
01173 
01174         // Form the closure:
01175         if (success) {
01176           value = NEW_CONSTR(ClosureVC, ((FuncEC*)func, c, false));
01177           if (recursive)
01178             ((ClosureVC*)value)->con =
01179               Context(NEW_CONSTR(AssocVC, (name, value)), c);
01180         }
01181         break;
01182       }
01183     case ModelVK:
01184       {
01185         // Name of the model:
01186         Text name;
01187         UnpickleText(name);
01188 
01189         // Sid of the model:
01190         ShortId sid;
01191         UnpickleInt32(sid);
01192 
01193         // VestaSource of the model root:
01194         // We leave master, pseudoInode, ac, rep, and attribs uninitialized,
01195         // since we know we do not need them.  We believe we do not need the
01196         // fptag, but we decided to pickle/unpickle them just in case.
01197         ShortId rootSid;
01198         UnpickleInt32(rootSid);
01199         FP::Tag rootTag;
01200         rootTag.Read(*bytes);
01201         read_size += FP::ByteCnt;
01202         VestaSource* root = NEW_CONSTR(VDirSurrogate, (0, rootSid));
01203         root->type = VestaSource::immutableDirectory;
01204         root->longid = LongId::fromShortId(rootSid);
01205         root->fptag = rootTag;
01206        
01207         // Fingerprint:
01208         FP::Tag tag;
01209         // Unpickle in network byte order
01210         tag.Read(*bytes);
01211         read_size += FP::ByteCnt;
01212         FP::Tag lidTag;
01213         lidTag.Read(*bytes);
01214         read_size += FP::ByteCnt;
01215 
01216         value = NEW_CONSTR(ModelVC, (name, sid, root, tag, lidTag));
01217         break;
01218       }
01219     case ErrorVK:
01220       {
01221         value = NEW_CONSTR(ErrorVC, (true));
01222         break;
01223       }
01224     default:
01225       {
01226         outputMu.lock();      
01227         Error("Bad value type in unpickling. Cache data may be corrupted!\n");
01228         outputMu.unlock();      
01229         success = false;
01230       }
01231     }
01232   }
01233   if (success) {
01234     value->path = path;
01235     success = UnpickleDPS(value->dps);
01236   }
01237   return success;
01238 }
01239 
01240 bool PickleC::checkNumBytesRead()
01241 {
01242   assert((unsigned int) bytes->tellg() == read_size);
01243 
01244   // Did we read less than all the bytes of the pickle?
01245   if(size > read_size)
01246     {
01247       outputMu.lock();
01248       cerr << ThreadLabel() << "Unpickling didn't read complete pickle (read "
01249            << read_size << " out of " << size << " bytes)" << endl
01250            << "(This is probably a bug; please report it.)" << endl;
01251       outputMu.unlock();
01252       return false;
01253     }
01254   // Did we read past the end of the pickle?  (Should be impossible
01255   // with a corrct stream implementation, but can't hurt to check.)
01256   else if(size < read_size)
01257     {
01258       ostringstream l_msg;
01259       l_msg << "Read past end of pickle (read "
01260             << read_size << " bytes, pickle was " << size << " bytes)";
01261       throw Evaluator::failure(l_msg.str(), false);
01262     }
01263   return true;
01264 }
01265 
01266 bool Pickle(Val value, /*OUT*/ VestaVal::T& vval) {
01267   PickleC pickle;
01268   bool success;
01269 
01270   try {
01271     // Record in pickle the current pickle version:
01272     pickle.PickleInt(currentPickleVersion);
01273     // Do the work:
01274     success = pickle.PickleVal(true, value);
01275   } catch (FS::Failure f) {
01276     outputMu.lock();    
01277     cerr << ThreadLabel() << "Pickling error: " << f;
01278     outputMu.unlock();    
01279     success = false;
01280   } catch (PrefixTbl::Overflow) {
01281     // Just pass this on to the caller.
01282     throw;
01283   } catch (...) {
01284     outputMu.lock();    
01285     cerr << ThreadLabel() << "Unknown exception in pickling.\n";
01286     outputMu.unlock();    
01287     success = false;
01288   }
01289   if (success) {
01290     vval.fp = value->FingerPrint();
01291     vval.bytes = (char *) pickle.getBytes();
01292     vval.len = pickle.getSize(); // Note: includes sanity check on size.
01293     vval.dis = pickle.dis;
01294     vval.prefixTbl = pickle.prefix;
01295   }
01296   return success;
01297 }
01298 
01299 bool Unpickle(const VestaVal::T& vval, const Context& c, /*OUT*/ Val& value) {
01300   try {
01301     PickleC pickle(vval.bytes, vval.len, vval.prefixTbl, c);
01302     // Make sure pickle versions are matched:
01303     int pickleVersion = -1;
01304     pickle.UnpickleInt(pickleVersion);
01305     // Do the work:
01306     if (pickleVersion != currentPickleVersion) {
01307       ostringstream l_msg;
01308       l_msg << "Pickle version mismatch.  (Got " << pickleVersion
01309             << ", expected " << currentPickleVersion << ")";
01310       throw Evaluator::failure(l_msg.str(), false);
01311     }
01312     bool success = pickle.UnpickleVal(true, value);
01313     // Sanity check that we read exactly the number of bytes in the
01314     // pickled value, no more no less.
01315     success = success && pickle.checkNumBytesRead();
01316     return success;
01317   } catch (FS::Failure f) {
01318     outputMu.lock();    
01319     cerr << ThreadLabel() << "Unpickling error: " << f << endl
01320          << "(This is probably a bug; please report it.)" << endl;
01321     outputMu.unlock();
01322   } catch (FS::EndOfFile f) {
01323     outputMu.lock();    
01324     cerr << ThreadLabel() << "EOF while unpickling." << endl
01325          << "(This is probably a bug; please report it.)" << endl;
01326     outputMu.unlock();    
01327   } catch (const char* report) {
01328     outputMu.lock();    
01329     cerr << ThreadLabel() << report << endl;
01330     outputMu.unlock(); 
01331   } catch (Evaluator::failure f) {
01332     outputMu.lock();    
01333     cerr << ThreadLabel() << f.msg << endl; 
01334     outputMu.unlock();
01335     throw;   
01336   } catch (...) {
01337     outputMu.lock();    
01338     cerr << ThreadLabel() << "Unknown exception in unpickling.\n";
01339     outputMu.unlock();    
01340   }
01341   return false;
01342 }

Generated on Mon May 8 00:48:39 2006 for Vesta by  doxygen 1.4.2