methodOop.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, 1995 LongView Technologies L.L.C. $Revision: 1.99 $ */
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 # include "incls/_precompiled.incl"
00025 # include "incls/_methodOop.cpp.incl"
00026 
00027 void methodOopDesc::decay_invocation_count(double decay_factor) {
00028   double new_count = (double) invocation_count() / decay_factor;
00029   set_invocation_count((int) new_count);
00030 
00031   // Take care of the block methods
00032   CodeIterator c(this);
00033   do {
00034     switch(c.code()) {
00035       case Bytecodes::push_new_closure_tos_0:      // fall through
00036       case Bytecodes::push_new_closure_tos_1:      // fall through
00037       case Bytecodes::push_new_closure_tos_2:      // fall through
00038       case Bytecodes::push_new_closure_context_0:  // fall through
00039       case Bytecodes::push_new_closure_context_1:  // fall through
00040       case Bytecodes::push_new_closure_context_2: {
00041           methodOop block_method = methodOop(c.oop_at(1));
00042           assert(block_method->is_method(), "must be method");
00043           block_method->decay_invocation_count(decay_factor);
00044         }
00045         break;
00046       case Bytecodes::push_new_closure_tos_n:      // fall through
00047       case Bytecodes::push_new_closure_context_n: {
00048           methodOop block_method = methodOop(c.oop_at(2));
00049           assert(block_method->is_method(), "must be method");
00050           block_method->decay_invocation_count(decay_factor);
00051         }
00052         break;
00053     }
00054   } while (c.advance());
00055 }
00056 
00057 void methodOopDesc::inc_sharing_count() {
00058   if (sharing_count() < _sharing_count_max) {
00059     set_sharing_count(sharing_count()+1);
00060   }
00061 }
00062 
00063 void methodOopDesc::dec_sharing_count() {
00064   if (sharing_count() > 0) {
00065     set_sharing_count(sharing_count()-1);
00066   }
00067 }
00068 
00069 void methodOopDesc::bootstrap_object(bootstrap* st) {
00070   memOopDesc::bootstrap_header(st);
00071   st->read_oop((oop*)&addr()->_debugInfo);
00072   st->read_oop((oop*)&addr()->_selector_or_method);
00073   set_counters(0, 0);
00074   st->read_oop((oop*)&addr()->_size_and_flags);
00075 
00076   for(int index = 1; index <= size_of_codes() * 4; )
00077     if (st->is_byte()) {
00078       byte_at_put(index, st->read_byte());
00079       index++;
00080     } else {
00081       st->read_oop((oop*) codes(index));
00082       index += 4;
00083     }
00084 }
00085 
00086 int methodOopDesc::next_bci_from(u_char* hp) const {
00087   // Computes the next bci
00088   // hp is the interpreter 'ip' kept in the activation
00089   // pointing to the next code to execute.
00090 
00091   // Fist the next bci is computed. Note the first index is 1.
00092   return (hp - (u_char*) addr()) - sizeof(methodOopDesc) + 1;
00093 }
00094 
00095 int methodOopDesc::bci_from(u_char* hp) const {
00096   // We find the current bci by searching from the beginning
00097   return find_bci_from(next_bci_from(hp));
00098 }
00099 
00100 
00101 int methodOopDesc::number_of_arguments() const {
00102   assert(is_blockMethod() || selector()->number_of_arguments() == nofArgs(), "just checking");
00103   return nofArgs();
00104 }
00105 
00106 
00107 int methodOopDesc::number_of_stack_temporaries() const {
00108   int n = 1;            // temporary 0 is always there
00109   u_char b0 = *codes(1);// if there's more than one temporary there's an allocate temp or allocate float at the beginning
00110   switch (b0) {
00111     case Bytecodes::allocate_temp_1: n += 1; break;
00112     case Bytecodes::allocate_temp_2: n += 2; break;
00113     case Bytecodes::allocate_temp_3: n += 3; break;
00114     case Bytecodes::allocate_temp_n: {
00115         u_char b1 = *codes(2);
00116         n += ((b1 == 0) ? 256 : b1);
00117       }
00118       break;
00119     case Bytecodes::float_allocate: {
00120         // One additional temp (temp1) for Floats::magic + additional
00121         // temps allocated in pairs to match to match one float temp.
00122         u_char b1 = *codes(2);
00123         n += 1 + b1*2;
00124       }
00125       break;
00126   }
00127   return n;
00128 }
00129 
00130 int methodOopDesc::float_offset(int float_no) const {
00131   assert(0 <= float_no && float_no < number_of_float_temporaries(), "float_no out of range");
00132   return float_section_start_offset() - float_no*floatSize/oopSize - 1;
00133 }
00134 
00135 symbolOop methodOopDesc::enclosing_method_selector() const {
00136   assert(is_blockMethod(), "must be block method");
00137   methodOop m = parent();
00138   while (m->is_blockMethod()) m = m->parent();
00139   return m->selector();
00140 }
00141 
00142 void methodOopDesc::print_value_for(klassOop receiver_klass, outputStream* st) {
00143   outputStream* s = st ? st : std;
00144   if (is_blockMethod()) {
00145     st->print("[] in ");
00146     enclosing_method_selector()->print_symbol_on(st);
00147   } else {
00148     selector()->print_symbol_on(s);
00149   }
00150   klassOop holder = receiver_klass->klass_part()->lookup_method_holder_for(this);
00151   if (holder) {
00152     s->print(" in ");
00153     holder->klass_part()->print_name_on(s);
00154   }
00155 }
00156 
00157 void methodOopDesc::print_codes() {
00158   ResourceMark rm;
00159   selector()->print_symbol_on(std);
00160   std->cr();
00161   MethodIterator mi(this, &MethodPrinterClosure(std));
00162   std->cr();
00163 }
00164 
00165 
00166 void methodOopDesc::pretty_print() {
00167   ResourceMark rm;
00168   prettyPrinter::print(this);
00169 }
00170 
00171 
00172 symbolOop methodOopDesc::selector() const {
00173   if (selector_or_method()->is_symbol()) return symbolOop(selector_or_method());
00174   return vmSymbols::selector_for_blockMethod();
00175 }
00176 
00177 
00178 methodOop methodOopDesc::parent() const {
00179   oop t = selector_or_method();
00180   return t->is_method() ? methodOop(t) : NULL;
00181 }
00182 
00183 
00184 methodOop methodOopDesc::home() const {
00185   methodOop m = methodOop(this);
00186   while (m->is_blockMethod()) m = m->parent();
00187   return m;
00188 }
00189 
00190 
00191 byteArrayOop methodOopDesc::source() {
00192   return oopFactory::new_symbol("<no source>");
00193 }
00194 
00195 
00196 objArrayOop methodOopDesc::tempInfo() {
00197   return debugInfo();
00198 }
00199 
00200 class methodStream {
00201  public:
00202   GrowableArray<oop>* result;
00203 
00204   methodStream() {
00205     result = new GrowableArray<oop>(1000);
00206   }
00207 
00208   void put_byte(int byte) {
00209     result->append(trueObj);
00210     result->append(as_smiOop(byte));
00211   }
00212 
00213   void put_word(int word) {
00214     char* p = (char*) &word;
00215     put_byte(p[0]);
00216     put_byte(p[1]);
00217     put_byte(p[2]);
00218     put_byte(p[3]);
00219   }
00220 
00221   void put_oop(oop obj) {
00222     result->append(falseObj);
00223     result->append(obj);
00224   }
00225 
00226   void align(u_char* hp) {
00227     u_char* end = (u_char*) (((int) hp + 3) & (~3));
00228     while (hp < end) {
00229       put_byte(255);
00230       hp++;
00231     }
00232   }
00233 };
00234 
00235 objArrayOop methodOopDesc::fileout_body() {
00236   // Convert sends into canonical form
00237   // Do not uncustomize since we need the mixin to do that.
00238   BlockScavenge bs;
00239   ResourceMark rm;
00240   methodStream out;
00241   
00242   CodeIterator c(this);
00243   do {
00244     if (Bytecodes::send_type(c.code()) != Bytecodes::no_send) {
00245       // Send
00246       Bytecodes::Code original = Bytecodes::original_send_code_for(c.code());
00247       out.put_byte(original);
00248       if (Bytecodes::format(original) == Bytecodes::BBOO) {
00249         out.put_byte(c.byte_at(1));
00250         out.align(c.hp() + 2);
00251       } else {
00252         out.align(c.hp() + 1);
00253       }
00254       out.put_oop( c.ic()->selector());
00255       out.put_oop( smiOop_zero);
00256     } else if (c.is_primitive_call()) {
00257       // Primitive call
00258       Bytecodes::Code original = Bytecodes::original_primitive_call_code_for(c.code());
00259       out.put_byte(original);
00260       out.align(c.hp() + 1);
00261       if (   c.code() == Bytecodes::prim_call
00262           || c.code() == Bytecodes::prim_call_failure
00263           || c.code() == Bytecodes::prim_call_self
00264           || c.code() == Bytecodes::prim_call_self_failure) {
00265         primitive_desc* pdesc = primitives::lookup((fntype) c.word_at(1));
00266         out.put_oop(pdesc->selector());
00267       } else {
00268         out.put_oop(c.oop_at(1));
00269       }
00270       if (Bytecodes::format(original) == Bytecodes::BOL) {
00271        out.put_word(c.word_at(5));
00272       }
00273     } else if (c.is_dll_call()) {
00274       // DLL call
00275       InterpretedDLL_Cache* ic = c.dll_cache();
00276       out.put_byte(c.code());
00277       out.align(c.hp() + 1);
00278       out.put_oop(ic->dll_name());
00279       out.put_oop(ic->funct_name());
00280       out.put_oop(smiOop_zero);
00281       out.put_byte(ic->number_of_arguments());
00282     } else {
00283       // Otherwise
00284       out.put_byte(c.code());
00285       switch(c.format()) {
00286         case Bytecodes::B:
00287           break;
00288         case Bytecodes::BB: 
00289           out.put_byte(c.byte_at(1));
00290           break;
00291         case Bytecodes::BBB:
00292           out.put_byte(c.byte_at(1));
00293           out.put_byte(c.byte_at(2));
00294           break;
00295         case Bytecodes::BBBB:
00296           out.put_byte(c.byte_at(1));
00297           out.put_byte(c.byte_at(2));
00298           out.put_byte(c.byte_at(3));
00299           break;
00300         case Bytecodes::BBO:
00301           out.put_byte(c.byte_at(1));
00302           out.align(c.hp() + 2);
00303           out.put_oop( c.oop_at(2));
00304           break;
00305         case Bytecodes::BBL:
00306           out.put_byte(c.byte_at(1));
00307           out.align(c.hp() + 2);
00308           out.put_word(c.word_at(2));
00309           break;
00310         case Bytecodes::BO:
00311           out.align(c.hp() + 1);
00312           out.put_oop( c.oop_at(1));
00313           break;
00314         case Bytecodes::BOL:
00315           out.put_oop( c.oop_at(1));
00316           out.align(c.hp() + 2);
00317           out.put_word(c.word_at(5));
00318           break;
00319         case Bytecodes::BLL:
00320           out.align(c.hp() + 1);
00321           out.put_word(c.word_at(1));
00322           out.put_word(c.word_at(5));
00323           break;
00324         case Bytecodes::BL:
00325           out.align(c.hp() + 1);
00326           out.put_word(c.word_at(1));
00327           break;
00328         case Bytecodes::BBS: {
00329             int length = c.byte_at(1) == 0 ? 256 : c.byte_at(1);
00330             out.put_byte(length);
00331             for(int index = 0; index < length; index++) {
00332               out.put_byte(c.byte_at(2 + index));
00333             }
00334             break;
00335         }
00336         default:
00337           std->print_cr("Format unknown %s", Bytecodes::format_as_string(c.format()));
00338           fatal("aborting");
00339       }
00340     }
00341   } while (c.advance());
00342   return oopFactory::new_objArray(out.result);
00343 }
00344 
00345 methodOopDesc::Method_Inlining_Info methodOopDesc::method_inlining_info() const {
00346   if (is_blockMethod()) return normal_inline;
00347   Method_Inlining_Info info = Method_Inlining_Info(get_unsigned_bitfield(flags(), methodInfoFlags, methodInfoSize));
00348   return info;
00349 }
00350 
00351 void methodOopDesc::set_method_inlining_info(Method_Inlining_Info info) {
00352   if (is_blockMethod()) return;
00353   set_flags(set_unsigned_bitfield(flags(), methodInfoFlags, methodInfoSize, info));
00354 }
00355 
00356 methodOopDesc::Block_Info methodOopDesc::block_info() const {
00357   assert(is_blockMethod(), "must be a block");
00358   return Block_Info(get_unsigned_bitfield(flags(), blockInfoFlags, blockInfoSize));
00359 }
00360 
00361 bool methodOopDesc::in_context_allocation(int bci) const {
00362   CodeIterator c(methodOop(this), bci);
00363   return c.code_type() == Bytecodes::new_context;
00364 }
00365 
00366 class BlockFinderClosure : public SpecializedMethodClosure {
00367 public:
00368   bool hasBlock;
00369   BlockFinderClosure() { hasBlock = false; }
00370   void allocate_closure(AllocationType type, int nofArgs, methodOop meth) { hasBlock = true; }
00371 };
00372 
00373 bool methodOopDesc::hasNestedBlocks() const {
00374   // should be a bit in the methodOop -- fix this, Robert (delete class above)
00375   BlockFinderClosure cl;
00376   MethodIterator it(methodOop(this), &cl);
00377   return cl.hasBlock;
00378 }
00379 
00380 
00381 // The following two functions map context numbers (as used in the interpreter
00382 // to access temps in enclosing scopes) to source-level lexical distances, and
00383 // vice versa.
00384 // Definitions: context no = number of indirections through contexts needed to
00385 //                           access temporary (0 -> temp is in current context)
00386 //              lex. dist. = difference in nesting levels between two scopes;
00387 //                           e.g., distance between a scope and its immediately
00388 //                           enclosing scope is 1
00389 
00390 int methodOopDesc::lexicalDistance(int contextNo) {
00391   methodOop m = this;
00392   int c = -1;
00393   int d = -1;
00394   while (c < contextNo) {
00395     if (m->allocatesInterpretedContext()) c++;
00396     m = m->parent();
00397     d++;
00398   };
00399   return d;
00400 }
00401 
00402 
00403 int methodOopDesc::contextNo(int lexicalDistance) {
00404   methodOop m = this;
00405   int c = -1;
00406   int d = -1;
00407   while (d < lexicalDistance) {
00408     if (m->allocatesInterpretedContext()) c++;
00409     m = m->parent();
00410     d++;
00411   }
00412   return c;
00413 }
00414 
00415 int methodOopDesc::context_chain_length() const {
00416   int length = 0;
00417   for (methodOop method = methodOop(this); method; method = method->parent()) {
00418     if (method->allocatesInterpretedContext())
00419       length++;
00420   }
00421   return length;
00422 }
00423 
00424 void methodOopDesc::clear_inline_caches() {
00425   // %skim the cream:
00426   //    if the method is not customized it has never been executed.
00427   if (!is_customized()) return;
00428 
00429   CodeIterator c(this);
00430   do {
00431     InterpretedIC* ic = c.ic();
00432     if (ic) {
00433       ic->clear();
00434     } else {
00435       // Call it for blocks
00436       switch(c.code()) {
00437       case Bytecodes::push_new_closure_tos_0:      // fall through
00438       case Bytecodes::push_new_closure_tos_1:      // fall through
00439       case Bytecodes::push_new_closure_tos_2:      // fall through
00440       case Bytecodes::push_new_closure_context_0:  // fall through
00441       case Bytecodes::push_new_closure_context_1:  // fall through
00442       case Bytecodes::push_new_closure_context_2: {
00443           methodOop block_method = methodOop(c.oop_at(1));
00444           assert(block_method->is_method(), "must be method");
00445           block_method->clear_inline_caches();
00446         }
00447         break;
00448       case Bytecodes::push_new_closure_tos_n:      // fall through
00449       case Bytecodes::push_new_closure_context_n: {
00450           methodOop block_method = methodOop(c.oop_at(2));
00451           assert(block_method->is_method(), "must be method");
00452           block_method->clear_inline_caches();
00453         }
00454         break;
00455       }
00456     }
00457   } while (c.advance());
00458 }
00459 
00460 void methodOopDesc::cleanup_inline_caches() {
00461   // %skim the cream:
00462   //    if the method is not customized it has never been executed.
00463   if (!is_customized()) return;
00464 
00465   CodeIterator c(this);
00466   do {
00467     InterpretedIC* ic = c.ic();
00468     if (ic) {
00469       ic->cleanup();
00470     } else {
00471       methodOop bm = c.block_method();
00472       if (bm) {
00473         bm->cleanup_inline_caches();
00474       }
00475     }
00476   } while (c.advance());
00477 }
00478 
00479 
00480 bool methodOopDesc::was_never_executed() {
00481   // skim the cream: if the method is not customized it has never been ecexuted.
00482   if (!is_customized()) return true;
00483 
00484   // return true if method looks like it was never executed
00485   if (invocation_count() != 0 || sharing_count() != 0) return false;
00486   CodeIterator c(this);
00487   do {
00488     InterpretedIC* ic = c.ic();
00489     if (ic && !ic->is_empty()) return false;
00490   } while (c.advance());
00491   return true;
00492 }
00493 
00494 int methodOopDesc::estimated_inline_cost(klassOop receiverKlass) {
00495   // the result of this calculation should be cached in the method; 8 bits are enough
00496   CodeIterator c(this);
00497   int cost = 0;
00498   do {
00499     cost += CostModel::cost_for(c.code());
00500     switch (c.code()) {
00501       case Bytecodes::push_new_closure_context_0:
00502       case Bytecodes::push_new_closure_context_1:
00503       case Bytecodes::push_new_closure_context_2:
00504       case Bytecodes::push_new_closure_tos_0:
00505       case Bytecodes::push_new_closure_tos_1:
00506       case Bytecodes::push_new_closure_tos_2: {
00507         methodOop m = methodOop(c.oop_at(1));
00508         assert(m->is_method(), "must be method");
00509         cost += m->estimated_inline_cost(receiverKlass);
00510         break;
00511       }
00512       case Bytecodes::push_new_closure_tos_n:
00513       case Bytecodes::push_new_closure_context_n: {
00514         methodOop m = methodOop(c.oop_at(2));
00515         assert(m->is_method(), "must be method");
00516         cost += m->estimated_inline_cost(receiverKlass);
00517         break;
00518       }
00519     }
00520     extern bool SuperSendsAreAlwaysInlined;
00521     if (Bytecodes::is_super_send(c.code()) && SuperSendsAreAlwaysInlined && receiverKlass) {
00522       klassOop mh = receiverKlass->klass_part()->lookup_method_holder_for(this);
00523       methodOop superMethod = mh ? lookupCache::compile_time_super_lookup(mh, selector()) : NULL;
00524       if (superMethod) cost += superMethod->estimated_inline_cost(receiverKlass);
00525     }
00526   } while (c.advance());
00527   return cost;
00528 }
00529 
00530 
00531 int methodOopDesc::find_bci_from(int nbci) const {
00532   CodeIterator c(methodOop(this));
00533   int prev_bci = 1;
00534   do {
00535     if (c.bci() == nbci) return prev_bci; 
00536     prev_bci = c.bci();
00537   } while (c.advance());
00538   return -1;
00539 }
00540 
00541 
00542 int methodOopDesc::next_bci(int bci) const {
00543   CodeIterator c(methodOop(this), bci);
00544   c.advance();
00545   return c.bci();
00546 }
00547 
00548 
00549 class ExpressionStackMapper : public MethodClosure {
00550  private:
00551    GrowableArray<int>* mapping;
00552    int target_bci;
00553 
00554    void map_push() { map_push(bci()); }
00555 
00556    void map_push(int b)  {
00557      // lprintf("push(%d)", bci);
00558      if (b >= target_bci) {
00559        abort();
00560      } else {
00561        mapping->push(b);
00562      }
00563    }
00564 
00565    void map_pop() {
00566      if (bci() >= target_bci) {
00567        abort();
00568      } else {
00569        // lprintf("pop(%d)", bci());
00570        mapping->pop();
00571      }
00572    }
00573 
00574    void map_send(bool has_receiver, int number_of_arguments) {
00575      if (has_receiver) map_pop();
00576      for(int i = 0; i < number_of_arguments; i++) map_pop();
00577      map_push();
00578    }
00579 
00580  public:
00581   ExpressionStackMapper(GrowableArray<int>* mapping, int target_bci) {
00582     this->mapping    = mapping;
00583     this->target_bci = target_bci;
00584   }
00585 
00586   void push_self()                              { map_push(); }
00587   void push_tos()                               { map_push(); }  
00588   void push_literal(oop obj)                    { map_push(); }
00589   void push_argument(int no)                    { map_push(); }
00590   void push_temporary(int no)                   { map_push(); }
00591   void push_temporary(int no, int context)      { map_push(); }
00592   void push_instVar(int offset)                 { map_push(); }
00593   void push_instVar_name(symbolOop name)        { map_push(); }
00594   void push_classVar(associationOop assoc)      { map_push(); }
00595   void push_classVar_name(symbolOop name)       { map_push(); }
00596 
00597   void push_global(associationOop obj)          { map_push(); }
00598 
00599   void pop()                                    { map_pop(); }
00600 
00601   void normal_send(InterpretedIC* ic)           { map_send(true,  ic->selector()->number_of_arguments()); }
00602   void self_send(InterpretedIC* ic)             { map_send(false, ic->selector()->number_of_arguments()); }
00603   void super_send(InterpretedIC* ic)            { map_send(false, ic->selector()->number_of_arguments()); }
00604 
00605   void double_equal()                           { map_send(true, 1); }
00606   void double_not_equal()                       { map_send(true, 1); }
00607 
00608   void method_return(int nofArgs)               { map_pop(); }
00609   void nonlocal_return(int nofArgs)             { map_pop(); }
00610 
00611   void allocate_closure(AllocationType type, int nofArgs, methodOop meth) {
00612     if (type == tos_as_scope) map_pop(); 
00613     map_push();
00614   }
00615 
00616   // nodes
00617   void if_node(IfNode* node);
00618   void cond_node(CondNode* node);
00619   void while_node(WhileNode* node);
00620   void primitive_call_node(PrimitiveCallNode* node);
00621   void dll_call_node(DLLCallNode* node);
00622 
00623   // call backs to ignore
00624   void allocate_temporaries(int nofTemps)                          {}
00625   void store_temporary(int no)                                     {}
00626   void store_temporary(int no, int context)                        {}
00627   void store_instVar(int offset)                                   {}
00628   void store_instVar_name(symbolOop name)                          {}
00629   void store_classVar(associationOop assoc)                        {}
00630   void store_classVar_name(symbolOop name)                         {}
00631 
00632   void store_global(associationOop obj)                            {} 
00633   void allocate_context(int nofTemps, bool forMethod = false)      {}
00634   void set_self_via_context()                                      {}
00635   void copy_self_into_context()                                    {}
00636   void copy_argument_into_context(int argNo, int no)               {}
00637   void zap_scope()                                                 {}
00638   void predict_prim_call(primitive_desc* pdesc, int failure_start) {}
00639   void float_allocate(int nofFloatTemps, int nofFloatExprs)        {}
00640   void float_floatify(Floats::Function f, int tof)                 { map_pop(); }
00641   void float_move(int tof, int from)                               {}
00642   void float_set(int tof, doubleOop value)                         {}
00643   void float_nullary(Floats::Function f, int tof)                  {}
00644   void float_unary(Floats::Function f, int tof)                    {}
00645   void float_binary(Floats::Function f, int tof)                   {}
00646   void float_unaryToOop(Floats::Function f, int tof)               { map_push(); }
00647   void float_binaryToOop(Floats::Function f, int tof)              { map_push(); }
00648 };
00649 
00650 
00651 void ExpressionStackMapper::if_node(IfNode* node) {
00652   if (node->includes(target_bci)) {
00653     if (node->then_code()->includes(target_bci)) {
00654       map_pop();
00655       MethodIterator i(node->then_code(), this);
00656     } else if (node->else_code() && node->else_code()->includes(target_bci)) {
00657       map_pop();
00658       MethodIterator i(node->else_code(), this);
00659     }
00660     abort();
00661   } else {
00662     map_pop();
00663     if (node->produces_result())
00664       map_push(node->begin_bci());
00665   }
00666 }
00667 
00668 
00669 void ExpressionStackMapper::cond_node(CondNode* node) {
00670   if (node->includes(target_bci)) {
00671     if (node->expr_code()->includes(target_bci)) {
00672       map_pop();
00673       MethodIterator i(node->expr_code(), this);
00674     }
00675     abort();
00676   } else {
00677     map_pop();
00678     map_push(node->begin_bci());
00679   }
00680 }
00681 
00682 
00683 void ExpressionStackMapper::while_node(WhileNode* node) {
00684   if (node->includes(target_bci)) {
00685     if (node->expr_code()->includes(target_bci))
00686       MethodIterator i(node->expr_code(), this);
00687     else if (node->body_code() && node->body_code()->includes(target_bci))
00688       MethodIterator i(node->body_code(), this);
00689     abort();
00690   }
00691 }
00692 
00693 
00694 void ExpressionStackMapper::primitive_call_node(PrimitiveCallNode* node) {
00695   int nofArgsToPop = node->number_of_parameters();
00696   for(int i = 0; i < nofArgsToPop; i++) map_pop();
00697 
00698   map_push();
00699   if (node->failure_code() && node->failure_code()->includes(target_bci)) {
00700     MethodIterator i(node->failure_code(), this);
00701   }
00702 }
00703 
00704 
00705 void ExpressionStackMapper::dll_call_node(DLLCallNode* node) {
00706   int nargs = node->nofArgs();
00707   for (int index = 0; index < nargs; index++)
00708     map_pop();
00709 }
00710 
00711 
00712 GrowableArray<int>* methodOopDesc::expression_stack_mapping(int bci) {
00713   GrowableArray<int>* mapping = new GrowableArray<int>(10);
00714   ExpressionStackMapper blk(mapping, bci);
00715   MethodIterator i(this, &blk);
00716 
00717   // reverse the mapping so the top of the expression stack is first
00718   // %todo:
00719   //    move reverse to GrowableArray
00720 
00721   GrowableArray<int>* result = new GrowableArray<int>(mapping->length());
00722   for (int index = mapping->length() - 1; index >= 0; index--) {
00723     result->push(mapping->at(index));
00724   }
00725   return result;
00726 }
00727 
00728 
00729 static void lookup_primitive_and_patch(u_char* p, u_char byte) {
00730   assert((int)p % 4 == 0, "first instruction supposed to be aligned");
00731   *p = byte;    // patch byte
00732   p += 4;       // advance to primitive name
00733   //(*(symbolOop*)p)->print_symbol_on();
00734   *(int*)p = (int)primitives::lookup(*(symbolOop*)p)->fn();
00735 }
00736 
00737 bool methodOopDesc::is_primitiveMethod() const {
00738   char b = *codes();
00739   switch (*codes()) {
00740     case Bytecodes::predict_prim_call:
00741       return true;
00742     case Bytecodes::predict_prim_call_failure:
00743       return true;
00744     case Bytecodes::predict_prim_call_lookup:
00745       lookup_primitive_and_patch(codes(), Bytecodes::predict_prim_call);
00746       return true;
00747     case Bytecodes::predict_prim_call_failure_lookup:
00748       lookup_primitive_and_patch(codes(), Bytecodes::predict_prim_call_failure);
00749       return true;
00750     default:
00751       return false;
00752   }
00753 }
00754 
00755 
00756 Bytecodes::Code methodOopDesc::special_primitive_code() const {
00757   assert(is_special_primitiveMethod(), "should only be called for special primitive methods");
00758   Bytecodes::Code code = Bytecodes::Code(*codes(2));
00759   assert(Bytecodes::send_type(code) == Bytecodes::predicted_send, "code or bytecode table inconsistent");
00760   return code;
00761 }
00762 
00763 
00764 methodOop methodOopDesc::methodOop_from_hcode(u_char* hp) {
00765   methodOop method = methodOop(as_memOop(Universe::object_start((oop*) hp)));
00766   assert(method->is_method(), "must be method");
00767   assert(method->codes() <= hp && hp < method->codes() + method->size_of_codes() * sizeof(oop),
00768          "h-code pointer not contained in method");
00769   return method;
00770 }
00771 
00772 
00773 int methodOopDesc::end_bci() const {
00774   int last_entry = this->size_of_codes() * 4;
00775   for (int index = 0; index < 4; index++)
00776     if (byte_at(last_entry-index) != Bytecodes::halt) return last_entry+1-index;
00777   fatal("should never reach the point");
00778   return 0;
00779 }
00780 
00781 
00782 InterpretedIC* methodOopDesc::ic_at(int bci) const {
00783    CodeIterator iterator(methodOop(this), bci);
00784    return iterator.ic();
00785 }
00786 
00787 methodOop methodOopDesc::block_method_at(int bci) {
00788   CodeIterator c(methodOop(this), bci);
00789   switch(c.code()) {
00790     case Bytecodes::push_new_closure_tos_0:      // fall through
00791     case Bytecodes::push_new_closure_tos_1:      // fall through
00792     case Bytecodes::push_new_closure_tos_2:      // fall through
00793     case Bytecodes::push_new_closure_context_0:  // fall through
00794     case Bytecodes::push_new_closure_context_1:  // fall through
00795     case Bytecodes::push_new_closure_context_2: {
00796         methodOop block_method = methodOop(c.oop_at(1));
00797         assert(block_method->is_method(), "must be method");
00798         return block_method;
00799       }
00800       break;
00801     case Bytecodes::push_new_closure_tos_n:      // fall through
00802     case Bytecodes::push_new_closure_context_n: {
00803         methodOop block_method = methodOop(c.oop_at(2));
00804         assert(block_method->is_method(), "must be method");
00805         return block_method;
00806       }
00807       break;
00808    }
00809   return NULL;
00810 }
00811 
00812 int methodOopDesc::bci_for_block_method(methodOop inner) {
00813   CodeIterator c(this);
00814   do {
00815     if (inner == block_method_at(c.bci()))
00816       return c.bci();
00817   } while (c.advance());
00818   ShouldNotReachHere();
00819   return 0;
00820 }
00821 
00822 void methodOopDesc::print_inlining_database_on(outputStream* st) {
00823   if (is_blockMethod()) {
00824     methodOop o = parent();
00825     o->print_inlining_database_on(st);
00826     st->print(" %d", o->bci_for_block_method(this));
00827   } else {
00828     selector()->print_symbol_on(st);
00829   }
00830 }
00831 
00832 // ContextMethodIterator is used in number_of_context_temporaries to
00833 // get information about context allocation
00834 class ContextMethodIterator : public SpecializedMethodClosure {
00835  private:
00836   enum { sentinel = -1 };
00837   int  count;
00838   bool _self_in_context;
00839 
00840  public:
00841   ContextMethodIterator() {
00842     count = sentinel;
00843     _self_in_context = false;
00844   }
00845 
00846   bool self_in_context() { return _self_in_context; }
00847 
00848   int number_of_context_temporaries() {
00849     assert(count != sentinel, "number_of_context_temporaries not set");
00850     return count;
00851   }
00852 
00853   void allocate_context(int nofTemps, bool forMethod) {
00854     assert(count == sentinel, "make sure it is not called more than one");
00855     count = nofTemps;
00856   }
00857 
00858   void copy_self_into_context() {
00859     _self_in_context = true; 
00860   }
00861 };
00862 
00863 int methodOopDesc::number_of_context_temporaries(bool* self_in_context) {
00864   // Use this for debugging only
00865   assert(allocatesInterpretedContext(), "can only be called if method allocates context");
00866   ContextMethodIterator blk;
00867   MethodIterator i(this, &blk);
00868   if (self_in_context) *self_in_context = blk.self_in_context();
00869   return blk.number_of_context_temporaries();
00870 }
00871 
00872 void methodOopDesc::customize_for(klassOop klass, mixinOop mixin) {
00873   assert(!is_customized() ||  klass != mixin->primary_invocation(), "should not recustomize to the same class"); 
00874   CodeIterator c(this);
00875   do {
00876     InterpretedIC* ic = c.ic();
00877     if (ic) ic->clear_without_deallocation_pic();
00878     switch(c.code()) {
00879 
00880       case Bytecodes::push_classVar_name:
00881       case Bytecodes::store_classVar_pop_name:
00882       case Bytecodes::store_classVar_name:
00883         c.customize_class_var_code(klass);
00884         break;
00885 
00886       case Bytecodes::push_classVar:
00887       case Bytecodes::store_classVar_pop:
00888       case Bytecodes::store_classVar:
00889         c.recustomize_class_var_code(mixin->primary_invocation(), klass);
00890         break;
00891 
00892       case Bytecodes::push_instVar_name:
00893       case Bytecodes::store_instVar_pop_name:
00894       case Bytecodes::store_instVar_name: 
00895       case Bytecodes::return_instVar_name:
00896         c.customize_inst_var_code(klass);
00897         break;
00898 
00899       case Bytecodes::push_instVar:
00900       case Bytecodes::store_instVar_pop:
00901       case Bytecodes::store_instVar: 
00902       case Bytecodes::return_instVar:
00903         c.recustomize_inst_var_code(mixin->primary_invocation(), klass);
00904         break;
00905 
00906       case Bytecodes::push_new_closure_tos_0:      // fall through
00907       case Bytecodes::push_new_closure_tos_1:      // fall through
00908       case Bytecodes::push_new_closure_tos_2:      // fall through
00909       case Bytecodes::push_new_closure_context_0:  // fall through
00910       case Bytecodes::push_new_closure_context_1:  // fall through
00911       case Bytecodes::push_new_closure_context_2: {
00912           methodOop block_method = methodOop(c.oop_at(1));
00913           assert(block_method->is_method(), "must be method");
00914           block_method->customize_for(klass, mixin);
00915         }
00916         break;
00917       case Bytecodes::push_new_closure_tos_n:      // fall through
00918       case Bytecodes::push_new_closure_context_n: {
00919           methodOop block_method = methodOop(c.oop_at(2));
00920           assert(block_method->is_method(), "must be method");
00921           block_method->customize_for(klass, mixin);
00922         }
00923         break;
00924     }
00925   } while (c.advance());
00926   // set customized flag
00927 
00928   int new_flags = addNth(flags(), isCustomizedFlag);
00929   set_size_and_flags(size_of_codes(), nofArgs(), new_flags);
00930 }
00931 
00932 void methodOopDesc::uncustomize_for(mixinOop mixin) {
00933   // Skim the cream
00934   if (!is_customized()) return;
00935 
00936   klassOop klass = mixin->primary_invocation();
00937   assert(klass->is_klass(), "primary invocation muyst be present");
00938 
00939   CodeIterator c(this);
00940   do {
00941     InterpretedIC* ic = c.ic();
00942     if (ic) ic->clear_without_deallocation_pic();
00943     switch(c.code()) {
00944       case Bytecodes::push_classVar:
00945       case Bytecodes::store_classVar_pop:
00946       case Bytecodes::store_classVar:
00947         c.uncustomize_class_var_code(mixin->primary_invocation());
00948         break;
00949 
00950       case Bytecodes::push_instVar:
00951       case Bytecodes::store_instVar_pop:
00952       case Bytecodes::store_instVar: 
00953       case Bytecodes::return_instVar:
00954         c.uncustomize_inst_var_code(mixin->primary_invocation());
00955         break;
00956 
00957       case Bytecodes::push_new_closure_tos_0:      // fall through
00958       case Bytecodes::push_new_closure_tos_1:      // fall through
00959       case Bytecodes::push_new_closure_tos_2:      // fall through
00960       case Bytecodes::push_new_closure_context_0:  // fall through
00961       case Bytecodes::push_new_closure_context_1:  // fall through
00962       case Bytecodes::push_new_closure_context_2: {
00963           methodOop block_method = methodOop(c.oop_at(1));
00964           assert(block_method->is_method(), "must be method");
00965           block_method->uncustomize_for(mixin);
00966         }
00967         break;
00968       case Bytecodes::push_new_closure_tos_n:      // fall through
00969       case Bytecodes::push_new_closure_context_n: {
00970           methodOop block_method = methodOop(c.oop_at(2));
00971           assert(block_method->is_method(), "must be method");
00972           block_method->uncustomize_for(mixin);
00973         }
00974         break;
00975     }
00976   } while (c.advance());
00977   // set customized flag
00978   int new_flags = subNth(flags(), isCustomizedFlag);
00979   set_size_and_flags(size_of_codes(), nofArgs(), new_flags);
00980 }
00981 
00982 methodOop methodOopDesc::copy_for_customization() const {
00983   // Copy this method
00984   int  len   = size();
00985   oop* clone = Universe::allocate_tenured(len);
00986   oop* to    = clone;
00987   oop* from  = (oop*) addr();
00988   oop* end   = to + len;
00989   while (to < end) *to++ = *from++;
00990 
00991   // Do the deep copy
00992   methodOop new_method = methodOop(as_memOop(clone));
00993   CodeIterator c(new_method);
00994   do {
00995     switch(c.code()) {
00996       case Bytecodes::push_new_closure_tos_0:      // fall through
00997       case Bytecodes::push_new_closure_tos_1:      // fall through
00998       case Bytecodes::push_new_closure_tos_2:      // fall through
00999       case Bytecodes::push_new_closure_context_0:  // fall through
01000       case Bytecodes::push_new_closure_context_1:  // fall through
01001       case Bytecodes::push_new_closure_context_2: {
01002           methodOop block_method = methodOop(c.oop_at(1));
01003           assert(block_method->is_method(), "must be method");
01004           methodOop new_block_method = block_method->copy_for_customization();
01005           new_block_method->set_selector_or_method(new_method);
01006           Universe::store(c.aligned_oop(1), new_block_method);
01007         }
01008         break;
01009       case Bytecodes::push_new_closure_tos_n:      // fall through
01010       case Bytecodes::push_new_closure_context_n: {
01011           methodOop block_method = methodOop(c.oop_at(2));
01012           assert(block_method->is_method(), "must be method");
01013           methodOop new_block_method = block_method->copy_for_customization();
01014           new_block_method->set_selector_or_method(new_method);
01015           Universe::store(c.aligned_oop(2), new_block_method);
01016         }
01017         break;
01018     }
01019   } while (c.advance());
01020   return new_method;
01021 }
01022 
01023 void methodOopDesc::verify_context(contextOop con) {
01024   // Check if we should expect a context
01025   if (!activation_has_context()) {
01026     warning("Activation has no context (0x%lx).", con);
01027   }
01028   // Check the static vs. dynamic chain length
01029   if (context_chain_length() != con->chain_length()) {
01030     warning("Wong context chain length (got %d expected %d)",
01031             con->chain_length(), context_chain_length());
01032   }
01033   // Check the context has no forward reference
01034   if (con->unoptimized_context() != NULL) {
01035     warning("Context is optimized (0x%lx).", con);
01036   }
01037 }
01038 
01039 // Traverses over the method including the blocks inside
01040 class TransitiveMethodClosure: public MethodClosure {
01041  public:
01042   void if_node(IfNode* node);
01043   void cond_node(CondNode* node);
01044   void while_node(WhileNode* node);
01045   void primitive_call_node(PrimitiveCallNode* node);
01046   void dll_call_node(DLLCallNode* node);
01047  
01048  public:
01049   virtual void inlined_send(symbolOop selector) {} 
01050 
01051  public:
01052   void allocate_temporaries(int nofTemps)                                       {}
01053   void push_self()                                                              {}
01054   void push_tos()                                                               {}
01055   void push_literal(oop obj)                                                    {}
01056   void push_argument(int no)                                                    {}
01057   void push_temporary(int no)                                                   {}
01058   void push_temporary(int no, int context)                                      {}
01059   void push_instVar(int offset)                                                 {}
01060   void push_instVar_name(symbolOop name)                                        {}
01061   void push_classVar(associationOop assoc)                                      {}
01062   void push_classVar_name(symbolOop name)                                       {}
01063   void push_global(associationOop obj)                                          {}
01064   void store_temporary(int no)                                                  {}
01065   void store_temporary(int no, int context)                                     {}
01066   void store_instVar(int offset)                                                {}
01067   void store_instVar_name(symbolOop name)                                       {}
01068   void store_classVar(associationOop assoc)                                     {}
01069   void store_classVar_name(symbolOop name)                                      {}
01070   void store_global(associationOop obj)                                         {}
01071   void pop()                                                                    {}
01072   void normal_send(InterpretedIC* ic)                                           {}
01073   void self_send  (InterpretedIC* ic)                                           {}
01074   void super_send (InterpretedIC* ic)                                           {}
01075   void double_equal()                                                           {}
01076   void double_not_equal()                                                       {}
01077   void method_return(int nofArgs)                                               {}
01078   void nonlocal_return(int nofArgs)                                             {}
01079   void allocate_closure(AllocationType type, int nofArgs, methodOop meth);
01080   void allocate_context(int nofTemps, bool forMethod)                           {}
01081   void set_self_via_context()                                                   {}
01082   void copy_self_into_context()                                                 {}
01083   void copy_argument_into_context(int argNo, int no)                            {}
01084   void zap_scope()                                                              {}
01085   void predict_prim_call(primitive_desc* pdesc, int failure_start)              {}
01086   void float_allocate(int nofFloatTemps, int nofFloatExprs)                     {}
01087   void float_floatify(Floats::Function f, int fno)                              {}
01088   void float_move(int fno, int from)                                            {}
01089   void float_set(int fno, doubleOop value)                                      {}
01090   void float_nullary(Floats::Function f, int fno)                               {}
01091   void float_unary(Floats::Function f, int fno)                                 {}
01092   void float_binary(Floats::Function f, int fno)                                {}
01093   void float_unaryToOop(Floats::Function f, int fno)                            {}
01094   void float_binaryToOop(Floats::Function f, int fno)                           {}
01095 };
01096 
01097 void TransitiveMethodClosure::allocate_closure(AllocationType type, int nofArgs, methodOop meth) {
01098   MethodIterator iter(meth, this);
01099 }
01100 
01101 void TransitiveMethodClosure::if_node(IfNode* node) {
01102   inlined_send(node->selector());
01103   MethodIterator iter(node->then_code(), this);
01104   if (node->else_code() != NULL) {
01105     MethodIterator iter(node->else_code(), this);
01106   }
01107 }
01108 
01109 void TransitiveMethodClosure::cond_node(CondNode* node) {
01110   inlined_send(node->selector());
01111   MethodIterator iter(node->expr_code(), this);
01112 }
01113 
01114 void TransitiveMethodClosure::while_node(WhileNode* node) {
01115   inlined_send(node->selector());
01116   MethodIterator iter(node->expr_code(), this);
01117   if (node->body_code() != NULL) {
01118     MethodIterator iter(node->body_code(), this);
01119   }
01120 }
01121 
01122 void TransitiveMethodClosure::primitive_call_node(PrimitiveCallNode* node) {
01123   inlined_send(node->name());
01124   if (node->failure_code() != NULL) {
01125     MethodIterator iter(node->failure_code(), this);
01126   }
01127 }
01128 
01129 void TransitiveMethodClosure::dll_call_node(DLLCallNode* node) {
01130   inlined_send(node->function_name());
01131   if (node->failure_code() != NULL) {
01132     MethodIterator iter(node->failure_code(), this);
01133   }
01134 }
01135 
01136 class ReferencedInstVarNamesClosure: public TransitiveMethodClosure {
01137  private:
01138   mixinOop mixin;
01139 
01140   void collect(int offset) {
01141     symbolOop name = mixin->primary_invocation()->klass_part()->inst_var_name_at(offset);
01142     if (name) result->append(name);
01143   }
01144 
01145   void collect(symbolOop name) {
01146     result->append(name);
01147   }
01148 
01149  public:
01150   void push_instVar(int offset)           { collect(offset); }
01151   void push_instVar_name(symbolOop name)  { collect(name);   }
01152   void store_instVar(int offset)          { collect(offset); }
01153   void store_instVar_name(symbolOop name) { collect(name);   }
01154  public:
01155   ReferencedInstVarNamesClosure(int size, mixinOop mixin) {
01156     this->result = new GrowableArray<oop>(size);
01157     this->mixin  = mixin;
01158   }
01159   GrowableArray<oop>* result; 
01160 };
01161 
01162 objArrayOop methodOopDesc::referenced_instance_variable_names(mixinOop mixin) const {
01163   ResourceMark rm;
01164   ReferencedInstVarNamesClosure blk(20, mixin);
01165   MethodIterator(methodOop(this), &blk);
01166   return oopFactory::new_objArray(blk.result);
01167 }
01168 
01169 class ReferencedClassVarNamesClosure: public TransitiveMethodClosure {
01170  private:
01171   void collect(symbolOop name) { result->append(name); }
01172  public:
01173   void push_classVar(associationOop assoc)  { collect(assoc->key()); }
01174   void push_classVar_name(symbolOop name)   { collect(name);         }
01175 
01176   void store_classVar(associationOop assoc) { collect(assoc->key()); }
01177   void store_classVar_name(symbolOop name)  { collect(name);         }
01178 
01179  public:
01180   ReferencedClassVarNamesClosure(int size) {
01181     result = new GrowableArray<oop>(size);
01182   }
01183   GrowableArray<oop>* result; 
01184 };
01185 
01186 objArrayOop methodOopDesc::referenced_class_variable_names() const {
01187   ResourceMark rm;
01188   ReferencedClassVarNamesClosure blk(20);
01189   MethodIterator(methodOop(this), &blk);
01190   return oopFactory::new_objArray(blk.result);
01191 }
01192 
01193 class ReferencedGlobalsClosure: public TransitiveMethodClosure {
01194  private:
01195   void collect(symbolOop selector) { result->append(selector); }
01196  public:
01197   void push_global(associationOop obj)  { collect(obj->key());}
01198   void store_global(associationOop obj) { collect(obj->key());}
01199 
01200  public:
01201   ReferencedGlobalsClosure(int size) {
01202     result = new GrowableArray<oop>(size);
01203   }
01204   GrowableArray<oop>* result; 
01205 };
01206 
01207 objArrayOop methodOopDesc::referenced_global_names() const {
01208   ResourceMark rm;
01209   ReferencedGlobalsClosure blk(20);
01210   MethodIterator(methodOop(this), &blk);
01211   return oopFactory::new_objArray(blk.result);
01212 }
01213 
01214 class SendersClosure: public TransitiveMethodClosure {
01215  private:
01216   void collect(symbolOop selector) { result->append(selector); }
01217 
01218   void float_op(Floats::Function f) {
01219     if (Floats::has_selector_for(f)) {
01220       collect(Floats::selector_for(f));
01221     }
01222   }
01223  public:
01224   void inlined_send(symbolOop selector) { collect(selector);       }
01225   void normal_send(InterpretedIC* ic)   { collect(ic->selector()); }
01226   void self_send  (InterpretedIC* ic)   { collect(ic->selector()); }
01227   void super_send (InterpretedIC* ic)   { collect(ic->selector()); }
01228   void double_equal()                   { collect(vmSymbols::double_equal());     }
01229   void double_not_equal()               { collect(vmSymbols::double_tilde());     }
01230 
01231   void float_floatify(Floats::Function f,    int fno) { float_op(f); }
01232   void float_nullary(Floats::Function f,     int fno) { float_op(f); }
01233   void float_unary(Floats::Function f,       int fno) { float_op(f); }
01234   void float_binary(Floats::Function f,      int fno) { float_op(f); }
01235   void float_unaryToOop(Floats::Function f,  int fno) { float_op(f); }
01236   void float_binaryToOop(Floats::Function f, int fno) { float_op(f); }
01237 
01238  public:
01239   SendersClosure(int size) {
01240     result = new GrowableArray<oop>(size);
01241   }
01242   GrowableArray<oop>* result; 
01243 };
01244 
01245 objArrayOop methodOopDesc::senders() const {
01246   ResourceMark rm;
01247   SendersClosure blk(20);
01248   MethodIterator(methodOop(this), &blk);
01249   return oopFactory::new_objArray(blk.result);
01250 }

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