nmethod.hpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.76 $ */
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 #ifdef DELTA_COMPILER
00025 
00026 // nmethods (native methods) are the compiled code versions of Delta
00027 // methods.
00028 
00029 struct nmFlags {
00030   unsigned int version:8;               // version number (0 = first version)
00031   unsigned int level:4;                 // optimization level
00032   unsigned int age:4;                   // age (in # of sweep steps)
00033 
00034   unsigned int state:2;                 // {alive, zombie, dead)
00035 
00036   unsigned int isUncommonRecompiled:1;  // recompiled because of uncommon trap?
00037   unsigned int isYoung:1;               // "young"? (recently recompiled)
00038   unsigned int isToBeRecompiled:1;      // to be recompiled as soon as it matures
00039   unsigned int is_block:1;              // tells whether is is a block nmethod;
00040 
00041   unsigned int markedForDeoptimization:1;// Used for stack deoptimization
00042 
00043   void clear();
00044 };
00045 
00046 // A nmethod has five parts:    
00047 //  1) header
00048 //  2) machine instructions             (mostly in NCodeBase)
00049 //  3) oop location information         (in OopNCode)
00050 //  4) mapping from block_closure_index to NonInlinedBlockScope offset
00051 //  5) debugging information
00052 //  6) dependency information
00053 
00054 class nmethod : public OopNCode {
00055  protected:
00056   uint16 _special_handler_call_offset;  // offset (in bytes) of call to special handler (*) (see comment below)
00057   uint16 _entry_point_offset;           // offset (in bytes) of entry point with class check
00058   uint16 _verified_entry_point_offset;  // offset (in bytes) of entry point without class check
00059   uint16 _scopeLen;
00060   uint16 _number_of_noninlined_blocks;
00061   uint16 _number_of_links;              // # of inline caches (including PICs) calling this nmethod
00062   uint16 _number_of_float_temporaries;  // # of floats in activation frame of this nmethod
00063   uint16 _float_section_size;           // size of float section in words
00064   uint16 _float_section_start_offset;   // offset of float section relative to frame pointer (in oops)
00065 
00066   int    _invocation_count;             // incremented for each nmethod invocation if CountExecution == true
00067   int    _uncommon_trap_counter;        // # of times uncommon traps have been executed
00068   nmFlags flags;                        // various flags to keep track of nmethod state
00069 
00070   // (*) At this address there's 5 bytes of extra space reserved to accomodate for a call to the zombie handler
00071   // if the nmethod is a zombie. If the nmethod is not a zombie, there's a call to StubRoutines::recompile_stub_entry()
00072   // instead (even if the nmethod doesn't count invocations). If the method turns zombie, this call is overwritten
00073   // by the beforementioned call, thereby making sure that the relocation information for the modified nmethod stays
00074   // valid. In both cases this address is jumped to via a short jump from one of the entry points.
00075 
00076   // Note: If it becomes important to save some space per nmethod, note that both _zombie_handler_jump_offset
00077   //       and _verified_entry_point_offset are less than 128 bytes away from _entry_point_offset, thus these
00078   //       offsets could be stored in one byte relative to _entry_point_offset.
00079 
00080    enum { alive = 0, zombie = 1, dead = 2 };
00081  
00082  public:
00083   char* insts() const                   { return (char*)(this + 1); }                           // machine instructions
00084   char* specialHandlerCall() const      { return insts() + _special_handler_call_offset; }      // call to special handler
00085   char* entryPoint() const              { return insts() + _entry_point_offset; }               // normal entry point
00086   char* verifiedEntryPoint() const      { return insts() + _verified_entry_point_offset; }      // e.p. if klass is correct
00087 
00088   // debugging information
00089   nmethodScopes* scopes() const         { return (nmethodScopes*) locsEnd(); }
00090   PcDesc*       pcs() const             { return (PcDesc*) scopes()->pcs(); }
00091   PcDesc*       pcsEnd() const          { return (PcDesc*) scopes()->pcsEnd(); }
00092 
00093   methodOop     method() const;
00094   klassOop      receiver_klass() const;
00095 
00096   uint16*       noninlined_block_offsets() const { return (uint16*) pcsEnd(); }
00097 
00098   
00099  public:
00100   LookupKey     key;                    // key for code table searching
00101 
00102   jumpTableID   main_id;     
00103   jumpTableID   promoted_id; 
00104 
00105   int  number_of_float_temporaries() const      { return _number_of_float_temporaries; }
00106   int  float_section_size() const               { return _float_section_size; }
00107   int  float_section_start_offset() const       { return _float_section_start_offset; }
00108   
00109   // Interface for number_of_callers
00110   int  number_of_links() const          { return _number_of_links; }
00111   void inc_number_of_links()            { _number_of_links++; }
00112   void dec_number_of_links()            { _number_of_links--; }
00113 
00114   // Interface for uncommon_trap_invocation
00115   int  uncommon_trap_counter() const    { return _uncommon_trap_counter; }
00116   void inc_uncommon_trap_counter()      { _uncommon_trap_counter++; }
00117 
00118   // Returns the parent nmethod if present, NULL otherwise
00119   nmethod* parent();
00120   // Returns the outermost nmethod, returns this if no parent is present.
00121   nmethod* outermost(); 
00122 
00123  protected:
00124   nmethod(Compiler* c);
00125   void* operator new(size_t size);
00126 
00127  public:
00128   friend nmethod* new_nmethod(Compiler* c);
00129   
00130   int    size() const                   { return instsEnd() - insts(); }        // size of code in bytes
00131 
00132   // Shift the pc relative information by delta.
00133   // Call this whenever the code is moved.
00134   void fix_relocation_at_move(int delta);
00135 
00136   void  moveTo(void* to, int size);
00137 
00138  public:
00139   bool  isNMethod() const               { return true; }
00140 
00141   // Flag accessing and manipulation.
00142   bool  isAlive() const                 { return flags.state == alive;  }
00143   bool  isZombie() const                { return flags.state == zombie; }
00144   bool  isDead()  const                 { return flags.state == dead;   }
00145 
00146   void  makeZombie(bool clearInlineCaches);
00147 
00148   bool  isUncommonRecompiled() const    { return flags.isUncommonRecompiled; }
00149 
00150   bool  isYoung();
00151   void  makeYoung()                     { flags.isYoung = 1; }
00152   void  makeOld();
00153 
00154   int   age() const                     { return flags.age; }
00155   void  incrementAge()                  { const int MaxAge = 15; flags.age = min(flags.age + 1, MaxAge); }
00156 
00157   bool  is_marked_for_deoptimization() const{ return flags.markedForDeoptimization; }
00158   void  mark_for_deoptimization()       { flags.markedForDeoptimization = 1; }
00159   void  unmark_for_deoptimization()     { flags.markedForDeoptimization = 0; }
00160 
00161   bool  isToBeRecompiled() const        { return flags.isToBeRecompiled; }
00162   void  makeToBeRecompiled()            { flags.isToBeRecompiled = 1; }
00163 
00164   bool  is_block() const                { return flags.is_block == 1; }
00165   bool  is_method() const               { return flags.is_block == 0; }
00166 
00167   int   level() const;
00168   void  setLevel(int newLevel)          { flags.level = newLevel; }
00169 
00170   int   version() const                 { return flags.version; }
00171   void  setVersion(int v);
00172 
00173  public:
00174   int estimatedInvocationCount() const; // approximation (not all calls have counters)
00175   int ncallers() const;                 // # of callers (# nmethods, *not* # of inline caches)
00176 
00177   bool  encompasses(void* p) const;
00178   
00179   // for zone LRU management
00180   int lastUsed() const                  { return LRUtable[0].lastUsed; }
00181   
00182   void  clear_inline_caches();
00183 
00184   void  cleanup_inline_caches();
00185 
00186   void  forwardLinkedSends(nmethod* to);
00187   
00188   void  unlink(); // unlink from codeTable, deps etc.
00189 
00190   // Removes the nmethod from the zone 
00191   void flush();
00192 
00193   // Returns the set of nmethods to invalidate if THIS nmethod is the root of invalidation.
00194   // The set will be this nmethod plus all offspring (seperately compiled block code).
00195   GrowableArray<nmethod*>* invalidation_family();
00196 
00197   // Tells whether this nmethod dependes on invalid classes (classes flagged invalid) 
00198   bool depends_on_invalid_klass();
00199 
00200  private:
00201   // Recursive helper function for invalidation_family()
00202   void add_family(GrowableArray<nmethod*>* result);
00203   
00204  protected:
00205   void  check_store();
00206  public:
00207   // Iterate over all oops in the nmethod
00208   void  oops_do(void f(oop*));
00209 
00210   bool  switch_pointers(oop from, oop to,
00211                         GrowableArray<nmethod*>* nmethods_to_invalidate);
00212   void relocate();
00213 
00214   // Verify operations
00215   void verify();
00216   void verify_expression_stacks();            // verify the expression stacks at all interrupt points
00217   void verify_expression_stacks_at(char* pc); // verify the expression stacks at pc
00218 
00219   // Iterates over all inline caches in the nmethod
00220   void CompiledICs_do(void f(CompiledIC*));
00221   
00222   // Iterates over all primitive inline caches in the nmethod
00223   void PrimitiveICs_do(void f(PrimitiveIC*));
00224 
00225   // programming and debugging
00226   PcDesc*    containingPcDesc(char* pc, PcDesc* start = NULL) const;
00227  protected:
00228   PcDesc*    containingPcDescOrNULL(char* pc, PcDesc* start = NULL) const;
00229  public:
00230 
00231   ScopeDesc* containingScopeDesc(char* pc) const;
00232 #ifdef DEBUG
00233   PcDesc*    correspondingPC(ScopeDesc* sd, int bci) const;
00234 #endif
00235 
00236   // For debugging
00237   CompiledIC*    IC_at(char* p) const;
00238   PrimitiveIC*   primitiveIC_at(char* p) const;
00239   oop*           embeddedOop_at(char* p) const;
00240 
00241   jumpTableEntry* jump_table_entry() const;
00242 
00243   // noninlined block mapping
00244   bool has_noninlined_blocks()       const;
00245   int  number_of_noninlined_blocks() const;
00246 
00247  protected:
00248   void validate_noninlined_block_scope_index(int index) const;
00249 
00250  public:
00251   NonInlinedBlockScopeDesc* noninlined_block_scope_at(int noninlined_block_index) const;
00252   methodOop                 noninlined_block_method_at(int noninlined_block_index) const;
00253   void                      noninlined_block_at_put(int noninlined_block_index, int offset) const;
00254   jumpTableEntry*           noninlined_block_jumpEntry_at(int noninlined_block_index) const;
00255 
00256 
00257   // Returns true if activation frame has been established. 
00258   bool has_frame_at(char* pc) const;
00259 
00260   // Returns true if pc is not in prologue or epilogue code.
00261   bool in_delta_code_at(char* pc) const;
00262   
00263   // Printing support
00264   void print();
00265   void printCode();
00266   void printLocs();
00267   void printPcs();
00268 
00269   void print_value_on(outputStream* st);
00270 
00271   // Inlining Database
00272   void print_inlining_database();
00273   void print_inlining_database_on(outputStream* st);
00274   GrowableArray<PcDesc*>* uncommonBranchList();
00275 
00276   // prints the inlining structure (one line per scope with indentation if there's no debug info)
00277   void print_inlining(outputStream* st = NULL, bool with_debug_info = false);
00278 
00279   friend nmethod* nmethodContaining(char* pc, char* likelyEntryPoint);
00280   friend nmethod* findNMethod(void* start);
00281   friend nmethod* findNMethod_maybe(void* start);
00282   
00283   friend nmethod* nmethod_from_insts(char* insts);
00284 
00285  public:
00286   // Counting & Timing
00287   int invocation_count() const          { return _invocation_count; }
00288   void set_invocation_count(int c)      { _invocation_count = c; }
00289 
00290   // Perform a sweeper task
00291   void sweeper_step(double decay_factor);
00292  private:
00293   inline void decay_invocation_count(double decay_factor);
00294 
00295  public: 
00296   static int invocationCountOffset()    { return (int)&((nmethod*)0)->_invocation_count; }
00297 
00298    // Support for preemption:
00299 
00300    // Overwrites the nmethod allowing trap at interrupt point.
00301    // After the overwrite data contains the information for restoring the nmethod.
00302    void overwrite_for_trapping(nmethod_patch* data);
00303 
00304    // Restores the nmethod 
00305    void restore_from_patch(nmethod_patch* data);
00306 };
00307 
00308 
00309 #endif

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