scopeDescRecorder.hpp

Go to the documentation of this file.
00001 /* Copyright 1994, LongView Technologies L.L.C. $Revision: 1.34 $ */
00002 /* Copyright (c) 2006, Sun Microsystems, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
00006 following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
00010           disclaimer in the documentation and/or other materials provided with the distribution.
00011     * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
00012           from this software without specific prior written permission.
00013 
00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
00015 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00016 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
00017 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00018 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00019 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00020 
00021 
00022 */
00023 
00024 
00025 #ifdef DELTA_COMPILER
00026 
00027 // ScopeDescRecorder provides the interface to generate scopeDescs for
00028 // optimized methods (nmethods).
00029 // To retrieve the generated information, use nmethodScopes
00030 
00031 class Array;
00032 class ByteArray;
00033 class NonInlinedBlockScopeNode;
00034 
00035 // Interface to generate scope information for an nmethod
00036 class ScopeDescRecorder: public ResourceObj {
00037  private:
00038   bool          _hasCodeBeenGenerated;
00039   Array*        oops;
00040   Array*        values;
00041   ByteArray*    codes;
00042   PcDescInfo    pcs;
00043 
00044   GrowableArray<klassOop>* dependants;
00045   int                  dependants_end;
00046 
00047   NonInlinedBlockScopeNode* nonInlinedBlockScopesHead;
00048   NonInlinedBlockScopeNode* nonInlinedBlockScopesTail;
00049 
00050  public:
00051   ScopeInfo root;
00052   
00053   // Returns the offset for a scopeDesc after generation of the scopeDesc info.
00054   int offset(ScopeInfo scope);
00055   int offset_for_noninlined_scope_node(NonInlinedBlockScopeNode* scope);
00056 
00057   ScopeDescRecorder(int scopeSize, // estimated size of scopes (in bytes)
00058                     int npcDesc);  // estimated number of PcDescs
00059 
00060   // Adds a method scope
00061   ScopeInfo addMethodScope(LookupKey*      key,                        // lookup key
00062                            methodOop       method,                     // result of the lookup
00063                            LogicalAddress* receiver_location,          // location of receiver
00064                            bool            allocates_compiled_context, // tells whether the code allocates a context
00065                            bool            lite         = false,
00066                            int             scopeID      = 0,
00067                            ScopeInfo       senderScope  = NULL, 
00068                            int             senderBCI    = IllegalBCI,
00069                            bool            visible      = false);
00070 
00071 
00072   // Adds an inlined block scope
00073   ScopeInfo addBlockScope(methodOop       method,                     // block method
00074                           ScopeInfo       parent,                     // parent scope
00075                           bool            allocates_compiled_context, // tells whether the code allocates a context
00076                           bool            lite             = false,
00077                           int             scopeID          = 0,
00078                           ScopeInfo       senderScope      = NULL, 
00079                           int             senderBCI        = IllegalBCI,
00080                           bool            visible          = false);
00081 
00082   // Adds a top level block scope
00083   ScopeInfo addTopLevelBlockScope(methodOop       method,                     // block method
00084                                   LogicalAddress* receiver_location,          // location of receiver
00085                                   klassOop        receiver_klass,             // receiver klass
00086                                   bool            allocates_compiled_context);// tells whether the code allocates a context
00087 
00088   // Adds an noninlined block scope
00089   // Used for retrieving information about block closure stubs
00090   NonInlinedBlockScopeNode* addNonInlinedBlockScope(methodOop block_method, ScopeInfo parent);
00091 
00092   // Interface for adding name nodes.
00093   void addTemporary        (ScopeInfo scope, int index, LogicalAddress* location); // all entries [0..max(index)] must be filled.
00094   void addContextTemporary (ScopeInfo scope, int index, LogicalAddress* location); // all entries [0..max(index)] must be filled.
00095   void addExprStack        (ScopeInfo scope, int bci,   LogicalAddress* location); // sparse array = some entries may be left empty.
00096 
00097   LogicalAddress* createLogicalAddress(NameNode* initial_value);
00098   void            changeLogicalAddress(LogicalAddress* location, NameNode* new_value, int pc_offset);
00099 
00100   // Providing the locations of the arguments is superfluous but is convenient for
00101   // verification. 
00102   //  - for top level scopes the argument locations are fixed (on the stack provided by the caller).
00103   //  - for inlined scopes the expression stack of the caller describes the argument locations.
00104   // %implementation-note:
00105   // For now the argument locations are saved since the function to compute expression stack has
00106   // not been implemented.
00107   void addArgument(ScopeInfo scope, int index, LogicalAddress* location);
00108 
00109   // Interface for creating the pc-offset <-> (ScopeDesc, bci) mapping.
00110   void addPcDesc(int pcOffset, ScopeInfo scope, int bci);
00111   void addIllegalPcDesc(int pcOffset);
00112 
00113   // Dependencies
00114   void add_dependant(LookupKey* key);
00115 
00116   // Returns the size of the generated scopeDescs.
00117   int size();
00118 
00119   // Copy the generated scopeDescs to 'addr'
00120   void copyTo(nmethod* nm);
00121 
00122   void verify(nmethodScopes* scopes);
00123 
00124   // Generates the the scopeDesc information.
00125   void generate();
00126 
00127  private:
00128   // Called before storring a location to resolve the context scope index into an offset
00129   Location convert_location(Location loc);
00130 
00131   ScopeInfo addScope(ScopeInfo scope, ScopeInfo senderScope);
00132   NonInlinedBlockScopeNode* addNonInlinedBlockScope(NonInlinedBlockScopeNode* scope);
00133 
00134   void genScopeDescHeader(u_char code, 
00135                           bool   lite,
00136                           bool   args,
00137                           bool   temps,
00138                           bool   context_temps,
00139                           bool   expr_stack,
00140                           bool   has_context,
00141                           bool   bigHeader);
00142 
00143   // Generate the collected dependecies 
00144   void generateDependencies();
00145 
00146   void emit_termination_node();
00147   void emit_illegal_node(bool is_last);
00148 
00149   // Returns true if was possible to save exprOffset and nextOffset in the
00150   // two pre-allocated bytes.
00151   int  updateScopeDescHeader(int offset, int next);
00152 
00153   void  updateExtScopeDescHeader(int offset, int next);
00154 
00155   inline int getValueIndex(int v);
00156   inline int getOopIndex(oop o);
00157   
00158   inline void genIndex(int index);
00159   void genValue(int v);
00160   void genOop(oop o);
00161 
00162   // Make the private stuff reachable from the internal nodes
00163   friend class NameNode;
00164   friend class LocationName;
00165   friend class ValueName;
00166   friend class MemoizedName;
00167   friend class BlockValueName;
00168   friend class IllegalName;
00169 
00170   friend class ScopeDescNode;
00171   friend class MethodScopeNode;
00172   friend class BlockScopeNode;
00173   friend class TopLevelBlockScopeNode;
00174   friend class NonInlinedBlockScopeNode;
00175 
00176   friend class LogicalAddress;
00177   friend class NameList;
00178 };
00179 
00180 // NameNode
00181 //  - LocationName
00182 //  - ValueName
00183 //  - MemoizedName
00184 //  - BlockValueName
00185 //  - IllegalName
00186 // this hierarchy is parallel to the NameDesc hierarchy in nameDesc.hpp
00187 
00188 class NameNode: public ResourceObj {            // abstract superclass of all NameNodes
00189  public:
00190   bool genHeaderByte(ScopeDescRecorder* rec, u_char code, bool is_last, int index);
00191 
00192   virtual bool hasLocation()    { return false; }
00193   virtual bool isIllegal()      { return false; }
00194   virtual Location location()   { ShouldNotCallThis(); return unAllocated; }
00195   virtual void generate(ScopeDescRecorder* rec, bool is_last) = 0;
00196 };
00197 
00198 // a LocationName describes a location; i.e., the corresponding source name (e.g., method temporary)
00199 // lives in this location for its entire lifetime
00200 class LocationName: public NameNode {
00201  private:
00202   Location l;
00203 
00204   void generate(ScopeDescRecorder* rec, bool is_last);
00205 
00206  public:
00207   LocationName(Location ln) { l = ln; }
00208   bool hasLocation()    { return true; }
00209   Location location()   { return l; }
00210 };
00211 
00212 // a ValueName is a constant; i.e., the corresponding source name is a compile-time constant
00213 // (maybe because it is a source constant, or because its computation has been constant-folded)
00214 class ValueName: public NameNode {
00215  private:
00216   oop value;
00217   
00218   void generate(ScopeDescRecorder* rec, bool is_last);
00219 
00220  public:
00221   ValueName(oop val) {
00222     value = val;
00223     assert(!val->is_block(), "should use BlockValueName");
00224   }
00225 };
00226 
00227 // a BlockValueName describes a block closure that has been completely optimized away; i.e., no
00228 // closure will ever be created at runtime during normal execution of the program
00229 class BlockValueName: public NameNode {
00230  private:
00231   methodOop block_method;   // The block method
00232   ScopeInfo parent_scope; // The scope where to find the context
00233 
00234   void generate(ScopeDescRecorder* rec, bool is_last);
00235 
00236  public:
00237   BlockValueName(methodOop block_method, ScopeInfo parent_scope) {
00238     this->block_method = block_method;
00239     this->parent_scope = parent_scope;
00240   }
00241 };
00242 
00243 // a MemoizedName describes a block closure that has been partially optimized away; i.e., a
00244 // closure may or may not be created at runtime. The closure's location is initialized to a special
00245 // value, and the actual closure is created on demand after testing if it has been created already.
00246 // If we ever look at this name during debugging and the block doesn't exist yet, we have to create
00247 // one and store it in the location.
00248 class MemoizedName: public NameNode {
00249  private:
00250   Location  loc;
00251   methodOop block_method;
00252   ScopeInfo parent_scope;
00253 
00254   void generate(ScopeDescRecorder* rec, bool is_last);
00255 
00256  public:
00257   MemoizedName(Location loc, methodOop block_method, ScopeInfo parent_scope) {
00258     this->loc          = loc;
00259     this->block_method = block_method;
00260     this->parent_scope = parent_scope;
00261   }
00262   bool hasLocation()    { return true; }
00263   Location location()   { return loc; }
00264 };
00265 
00266 // newValueName creates a ValueName or BlockValueName (if value is a block)
00267 NameNode* newValueName(oop value);      
00268 
00269 // an IllegalName marks a name that cannot be inspected at runtime because it is never visible
00270 // at any interrupt point (i.e., it is live only between two interrupt points)
00271 // mainly exists for compiler/runtime system debugging
00272 class IllegalName: public NameNode {
00273  private:
00274   bool isIllegal()  { return true; }
00275   void generate(ScopeDescRecorder* rec,  bool is_last);
00276 };
00277 
00278 enum {
00279   LOCATION_CODE,
00280   VALUE_CODE,
00281   BLOCKVALUE_CODE,
00282   MEMOIZEDBLOCK_CODE
00283 };
00284 
00285 // helper data structures used during packing and unpacking
00286 class nameDescHeaderByte : public ValueObj {
00287  private:
00288   u_char byte; 
00289   static const u_char code_width;
00290   static const u_char index_width;
00291   static const u_char is_last_bit_num;
00292   static const u_char max_code;
00293 
00294   u_char raw_index() { return lowerBits(byte >> code_width, index_width); }
00295 
00296  public:
00297   static const u_char max_index;
00298   static const u_char no_index;
00299   static const u_char termination_index;
00300   static const u_char illegal_index;
00301 
00302   u_char value() { return byte; }
00303 
00304   u_char code()  {
00305     return lowerBits(byte, code_width); 
00306   }
00307 
00308   u_char index()          {
00309     assert(has_index(), "must have valid index");
00310     return raw_index();
00311   }
00312 
00313   bool is_illegal()     { return raw_index() == illegal_index;     }
00314   bool is_termination() { return raw_index() == termination_index; }
00315   bool is_last()        { return isSet(byte, is_last_bit_num);     }
00316   bool has_index()      { return raw_index() <= max_index;         }
00317   
00318   void pack(u_char code, bool is_last, u_char i) {
00319     assert( code <= max_code,  "code to high");
00320     assert( i    <= no_index,  "index to high");
00321     byte = addBits(i << code_width, code);
00322     if (is_last) byte = setNth(byte, is_last_bit_num);
00323   }
00324 
00325   void pack_illegal(bool is_last) {
00326     byte = addBits(illegal_index << code_width, 0);
00327     if (is_last) byte = setNth(byte, is_last_bit_num);
00328   }
00329 
00330   void pack_termination(bool is_last) {
00331     byte = addBits(termination_index << code_width, 0);
00332     if (is_last) byte = setNth(byte, is_last_bit_num);
00333   }
00334 
00335   void unpack(u_char value) { byte = value; }
00336 };
00337 
00338 class scopeDescHeaderByte : public ValueObj {
00339  private:
00340   u_char byte;
00341   static const u_char code_width;
00342   static const u_char max_code;
00343   static const u_char lite_bit_num;
00344   static const u_char args_bit_num;
00345   static const u_char temps_bit_num;
00346   static const u_char context_temps_bit_num;
00347   static const u_char expr_stack_bit_num;
00348   static const u_char context_bit_num;
00349  public:
00350   u_char value()                { return byte; }
00351   u_char code()                 { return lowerBits(byte, code_width);        }
00352   bool   is_lite()              { return isSet(byte, lite_bit_num);          }
00353   bool   has_args()             { return isSet(byte, args_bit_num);          }
00354   bool   has_temps()            { return isSet(byte, temps_bit_num);         }
00355   bool   has_context_temps()    { return isSet(byte, context_temps_bit_num); }
00356   bool   has_expr_stack()       { return isSet(byte, expr_stack_bit_num);    }
00357   bool   has_compiled_context() { return isSet(byte, context_bit_num);       }
00358  
00359   bool   has_nameDescs()     { return has_args()
00360                                    || has_temps()
00361                                    || has_context_temps()
00362                                    || has_expr_stack(); }
00363 
00364   void pack(u_char code, bool lite, bool args, bool temps, bool context_temps, bool expr_stack, bool has_compiled_context) {
00365     assert( code <= max_code, "code to high");
00366     byte = code;
00367     if (lite)                   byte = setNth(byte, lite_bit_num);
00368     if (args)                   byte = setNth(byte, args_bit_num);
00369     if (temps)                  byte = setNth(byte, temps_bit_num);
00370     if (context_temps)          byte = setNth(byte, context_temps_bit_num);
00371     if (expr_stack)             byte = setNth(byte, expr_stack_bit_num);
00372     if (has_compiled_context)   byte = setNth(byte, context_bit_num);
00373   }
00374 
00375   void unpack(u_char value) { byte = value; }
00376 };
00377 
00378 # define BYTE_WIDTH       8 
00379 # define EXTENDED_INDEX   nthMask(BYTE_WIDTH)
00380 # define MAX_INLINE_VALUE nthMask(BYTE_WIDTH-1)
00381 
00382 enum {
00383   METHOD_CODE,
00384   BLOCK_CODE,
00385   TOPLEVELBLOCK_CODE,
00386   NONINLINED_BLOCK_CODE
00387 };
00388 
00389 #endif

Generated on Mon Oct 9 13:37:27 2006 for Strongtalk VM by  doxygen 1.4.7