Cint incremental bytecode compiler

# Cint incremental bytecode compilation mode ################################

In order to improve interpreter speed, cint has incremental bytecode compiler.
The bytecode compiler is excited by loop commands, for, while, do. You can
choose level of bytecode optimization by '-O[n]' command line option or
'O[n]' interactive command.

  O0   : No bytecode compilation, everything is interpreted. very slow
  O1   : Loops are bytecode compiled
  O2   :  + some instructions are optimized
  O3   :  + some more instructions are optimized
  O4   :  + function called within a loop is bytecode compiled
  O5   : All interpreted functions will be bytecode compiled when called

Default is O4. You need to consult cint@pcroot.cern.ch when using O5.
There is another level O10 , but this can be only used with special care.

 (Not recommended, only experimental)
  O10  : all interpreted functions will be bytecode compiled when loaded

Bytecode compilation fails when it encounters limitations described in this
document. In such case, bytecode is discarded and the code is interpreted.


# Incremental bytecode compilation of loops #################################

For loop in follwing example is compiled as bytecode in the first iteration, 
2nd to 10000th iterations execute bytecode. 

    const int NUM=10000;
    double ary[NUM];
    for(int i=0;i<NUM;i++) {  // bytecode
      ary[i] = i*2;           // bytecode
    }                         // bytecode


If interpreted function is called with in the loop, that function is compiled
as bytecode too. For example, function f() called with in for loop is compiled
as bytecode.
   
    void f(double *p,int i) {  // bytecode
      p[i] = i*2;              // bytecode
    }                          // bytecode

    g() {
      const int NUM=10000;
      double ary[NUM];
      for(int i=0;i<NUM;i++) {  // bytecode
        f(ary,i);               // bytecode
      }                         // bytecode
    }

# Limitations of bytecode compilation ######################################

Cint bytecode compiler has some limitations. To enjoy confortable execution
speed, your code must conform to following guideline.

* Don't use 'goto' statement.  Use break or continue statement instead.

   for(int i=0;i<10000;i++) {
     if(i=1000) goto end;     // bytecode aborted, will be slow
   }
   end:

   for(int i=0;i<10000;i++) { // bytecode
     if(i=1000) break;        // bytecode,  this is fine
   }                          // bytecode

* Don't use 'switch' statement. Use if-else-if instead.

   for(int i=0;i<10000;i++) {
     switch(i) {              // X bytecode aborted, will be slow
     case 1: doit1(); break;
     case 2: doit2(); break;
     default: dodefault(); break;
     }
   }

   for(int i=0;i<10000;i++) { // bytecode
     if(1==i) doit1();        // bytecode
     else if(2==i) doit2();   // bytecode
     else dodefault();        // bytecode
   }                          // bytecode

* Function called within loop, we have relaxed limitation.

   void f1(int i) {           // bytecode
     if(100=i) goto end;      // bytecode, goto is OK
     switch(i) {              // bytecode, switch is OK
     case 1: doit1(); break;  // bytecode
     case 2: doit2(); break;  // bytecode
     default:                 // bytecode
      dodefault(); break;     // bytecode
     }                        // bytecode
    end:                      // bytecode
   }                          // bytecode

   void f2(int i) {           // bytecode
     if(100=i) return;        // bytecode
     if(1==i) doit1();        // bytecode
     else if(2==i) doit2();   // bytecode
     else dodefault();        // bytecode
   }                          // bytecode

   g() {
     for(int i=0;i<NUM;i++) {  // bytecode
       f1(i);                  // bytecode, f1 runs bytecode
       f2(i);                  // bytecode, f2 runs bytecode
     }                         // bytecode
   }

* There are additional limitations for the bytecode function. 
    - Don't declare automatic class object, use pointer and new statement.
    - Don't return class object, use reference or pointer 
    - Don't take class object as argument, use reference or pointer 
    - Function must be less than 2000 lines
    - No array and/or struct initialization 

   class A { ... } ; // percompiled class
   struct B { double a,b; }; 

   A f1() {                   // X returning class object 
     A a;                     // X automatic class object decl, abort bytecode
     int x[5]={1,2,3,4,5};    // X array initialization
     B b = { 1.2, 3.4 };      // X struct initialization
     a.Doit();
        .
     // X more than 2000 lines of code
        .
     return(a); 
   }

   A* f2(A* pd) {             // bytecode, reference or pointer is fine
     A *p = new A;            // bytecode, new PrecompiledClass is fine
     p->Doit();               // bytecode
     delete p;                // bytecode
     return(pd);              // bytecode
   }                          // bytecode

   g() {
     for(int i=0;i<NUM;i++) {  // bytecode
       f1(i);                  // bytecode, inside f1 remain interpreted
       f2(i);                  // bytecode, f2 runs bytecode
     }                         // bytecode
   }
 

# Bytecode compilation check #############################################

Unfortunately, above description is not very thorough. 
There are a few other limitations which are sabtle and hard to explain.
To check bytecode compilation status, you can use following technique.
 
* Use -v command line option or 'debug' command from the interactive 
  interface. Bytecode compiler displays messages.

    $ cint -v myprog.cxx

    $ cint iostream.h
    cint> debug
    cint> { for(int i=0;i<5;i++) cout << i << endl; }
    !!!bytecode compilation operator<< start FILE:/tmp/01030aaa LINE:1
    Bytecode compilation of operator<< successful FILE:iostream.h LINE:346
    0
    Bytecode loop compilation successful FILE:/tmp/01030aaa LINE:1
    1
    2
    3
    4
    cint>
 
* After running the loop, use 'func' or 'class [classname]' command to 
   show list of function. Those which successfully compiled as bytecode 
   are marked with '*'.

   cint> func
        .
   (compiled)        0:0    0 public: istream& ws(istream&);
   iostream.h      346:1  * 0 public: ostream& operator<<(ostream& ostr,...
   iostream.h      349:1    0 public: ostream& operator<<(ostream& ostr,...
   iostream.h      352:1    0 public: ostream& operator<<(ostream& ostr,...
        .
