jumpTable.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, LongView Technologies L.L.C. $Revision: 1.33 $ */
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 
00026 #ifdef DELTA_COMPILER
00027 
00028 # include "incls/_jumpTable.cpp.incl"
00029 
00030 static const char halt_instruction = '\xF4';
00031 static const char jump_instruction = '\xE9';
00032 
00033 
00034 char* jumpTable::allocate_jump_entries(int size) {
00035   return AllocateHeap(size * jumpTableEntry::size(), "jump table");
00036 }
00037 
00038 jumpTableEntry* jumpTable::jump_entry_for_at(char* entries, int index) {
00039   return (jumpTableEntry*) &entries[index * jumpTableEntry::size()];
00040 }
00041 
00042 jumpTable::jumpTable() {
00043   length  = Universe::current_sizes.jump_table_size;
00044   assert(length < 32 * K, "must change code to handle >32K entries");
00045   entries = allocate_jump_entries(length);
00046   init();
00047 }
00048 
00049 jumpTableID jumpTable::allocate(int number_of_entries) {
00050   int id                = newID();
00051   jumpTableEntry* entry = major_at(id);
00052 
00053   assert(entry->is_unused(), "cannot allocate used jump entry");
00054   if (number_of_entries == 1) {
00055     entry->initialize_nmethod_stub(NULL);
00056     return jumpTableID(id);
00057   } else {
00058     char* new_block = allocate_jump_entries(number_of_entries);
00059     // Initialize the first entry as a nmethod stub
00060     jump_entry_for_at(new_block, 0)->initialize_nmethod_stub(NULL);
00061     // initialize the rest as block closure stubs
00062     for(int i = 1; i < number_of_entries; i++) {
00063       jump_entry_for_at(new_block, i)->initialize_block_closure_stub();
00064     }
00065     entry->initialize_as_link(new_block);
00066     return jumpTableID(id,0);
00067   }
00068 }
00069 
00070 jumpTable::~jumpTable() { free(entries); }
00071 
00072 jumpTableEntry* jumpTable::major_at(u_short index) { 
00073   return jump_entry_for_at(entries, index);
00074 }
00075 
00076 jumpTableEntry* jumpTable::at(jumpTableID id) {
00077   assert(id.is_valid(), "invalid ID");
00078   if (!id.has_minor()) return major_at(id.major());
00079   return jump_entry_for_at(major_at(id._major)->link(), id._minor);
00080 }
00081 
00082 void jumpTable::init() {
00083   // free list: firstFree keeps first free index, entries[firstFree] keeps index
00084   // of next free element, etc.
00085   firstFree = usedIDs = 0;
00086   for (int i = 0; i < length; i++)
00087     major_at(i)->initialize_as_unused(i+1);
00088 }
00089 
00090 int jumpTable::newID() {
00091   int id = firstFree;
00092   if (id >= length - 2) fatal("grow not implemented");
00093   firstFree = major_at(firstFree)->next_free();
00094   usedIDs++;
00095   return id;
00096 }
00097 
00098 int jumpTable::peekID() {
00099   return firstFree;
00100 }
00101 
00102 void jumpTable::freeID(int index) {
00103   assert(index >= 0 && index < length && index != firstFree, "invalid ID");
00104   if (major_at(index)->is_link()) {
00105     // free the chunk 
00106     free(major_at(index)->link());
00107   }
00108   major_at(index)->initialize_as_unused(firstFree);
00109   firstFree = index;
00110   usedIDs--;
00111   assert(usedIDs >= 0, "freed to many IDs");
00112 }
00113 
00114 void jumpTable::print() {
00115   std->print_cr("jumpTable %#lx: capacity %ld (%ld used)", this, length, usedIDs);
00116   for (int i = 0; i < length; i++) {
00117     if (!major_at(i)->is_unused()) {
00118       std->print(" %3d: ", i);
00119       major_at(i)->print();
00120     }
00121   }
00122 }
00123 
00124 char* jumpTable::compile_new_block(blockClosureOop blk) {
00125   // Called from the compile_block stub routine (see StubRoutines)
00126   BlockScavenge bs;
00127   ResourceMark rm;
00128   nmethod* nm = compile_block(blk);
00129 
00130   // return the entry point for the new nmethod.
00131   return nm->entryPoint();
00132 }
00133 
00134 nmethod* jumpTable::compile_block(blockClosureOop closure) {
00135   // compute the scope for noninlined block
00136   int index;
00137   nmethod* parent = closure->jump_table_entry()->parent_nmethod(index); 
00138   NonInlinedBlockScopeDesc* scope = parent->noninlined_block_scope_at(index);
00139 
00140   // compile the top-level block nmethod
00141   VM_OptimizeBlockMethod op(closure, scope);
00142   VMProcess::execute(&op);
00143   nmethod* nm = op.method();
00144 
00145   // patch the jump entry with the entry point of the compiled nmethod
00146   closure->jump_table_entry()->set_destination(nm->entryPoint());
00147 
00148   jumpTableEntry* a = closure->jump_table_entry();
00149   jumpTableEntry* b = nm->jump_table_entry();
00150   assert(a == b, "jump table discrepancy");
00151   return nm;
00152 }
00153 
00154 static const char nmethod_entry        = 0;
00155 static const char block_closure_entry  = 1;
00156 static const char link_entry           = 2;
00157 static const char unused_entry         = 3;
00158 
00159 inline jumpTableEntry* jumpTableEntry::previous_stub() const {
00160   return (jumpTableEntry*) (((char*) this) - size());
00161 }
00162 
00163 inline jumpTableEntry* jumpTableEntry::next_stub() const {
00164   return (jumpTableEntry*) (((char*) this) + size());
00165 }
00166 void jumpTableEntry::fill_entry(char instr, char* dest, char state) {
00167   *jump_inst_addr()   = instr;
00168   *destination_addr() = dest;
00169   *state_addr()       = state;
00170 }
00171 
00172 void jumpTableEntry::initialize_as_unused(int index) {
00173   fill_entry(halt_instruction, (char*) index, unused_entry);
00174 }
00175 
00176 void jumpTableEntry::initialize_as_link(char* link) {
00177   fill_entry(halt_instruction, link, link_entry);
00178 }
00179 
00180 void jumpTableEntry::initialize_nmethod_stub(char* dest) {
00181   fill_entry(jump_instruction, dest - (int) state_addr(), nmethod_entry);
00182 }
00183 
00184 void jumpTableEntry::initialize_block_closure_stub() {
00185   fill_entry(jump_instruction,
00186              StubRoutines::compile_block_entry() - (int) state_addr(),
00187              block_closure_entry);
00188 }
00189 
00190 bool jumpTableEntry::is_nmethod_stub() const { 
00191   return state() == nmethod_entry;
00192 }
00193 
00194 bool jumpTableEntry::is_block_closure_stub() const {
00195   return state() == block_closure_entry;
00196 }
00197 
00198 bool jumpTableEntry::is_unused() const { 
00199   return state() == unused_entry;
00200 }
00201 
00202 bool jumpTableEntry::is_link() const { 
00203   return state() == link_entry;
00204 }
00205 
00206 char* jumpTableEntry::link() const {
00207   return *destination_addr();
00208 }
00209 
00210 char** jumpTableEntry::destination_addr() const { 
00211   return (char**) (((char*) this) + sizeof(char));
00212 }
00213 
00214 char* jumpTableEntry::destination() const {
00215   return *destination_addr() + (int) state_addr();
00216 }
00217 
00218 void jumpTableEntry::set_destination(char* dest) {
00219   *destination_addr() = dest - (int) state_addr();
00220 }
00221 
00222 int jumpTableEntry::next_free() const {
00223   assert(is_unused(), "must be a unused entry");
00224   return (int) *destination_addr();
00225 }
00226 
00227 nmethod* jumpTableEntry::method() const {
00228   assert(is_nmethod_stub(), "must be a nmethod_stub");
00229   return Universe::code->findNMethod(destination());
00230 }
00231 
00232 bool jumpTableEntry::block_has_nmethod() const {
00233   assert(is_block_closure_stub(), "must be a block_closure_stub");
00234   return destination() != StubRoutines::compile_block_entry();
00235 }
00236 
00237 nmethod* jumpTableEntry::block_nmethod() const {
00238   assert(is_block_closure_stub(), "must be a block_closure_stub");
00239   if (block_has_nmethod()) {
00240     return Universe::code->findNMethod(destination());
00241   } else {
00242     return NULL;
00243   }
00244 }
00245 
00246 methodOop jumpTableEntry::block_method() const {
00247   assert(is_block_closure_stub(), "must be a block_closure_stub");
00248   if (block_has_nmethod()) {
00249     nmethod* nm = Universe::code->findNMethod(destination());
00250     assert(nm != NULL, "nmethod must exists");
00251     return nm->method();
00252   } else {
00253     int index;
00254     jumpTableEntry* pe = parent_entry(index);
00255     // find methodOop inside the nmethod:
00256     return pe->method()->noninlined_block_method_at(index);
00257   }
00258 }
00259 
00260 jumpTableEntry* jumpTableEntry::parent_entry(int& index) const {
00261   assert(is_block_closure_stub(), "must be a block_closure_stub");
00262   // search back in the jump table to find the nmethod stub
00263   // responsible for this block closure stub.
00264   jumpTableEntry* result = (jumpTableEntry*)this;
00265   index = 0;
00266   do {
00267     index++;
00268     result = result->previous_stub();
00269   }
00270   while(result->is_block_closure_stub());
00271   return result;
00272 }
00273 
00274 nmethod* jumpTableEntry::parent_nmethod(int& index) const {
00275   return parent_entry(index)->method();
00276 }
00277 
00278 void jumpTableEntry::print() {
00279   if (is_unused()) { 
00280     std->print_cr("Unused {next = %d}", (int) destination());
00281     return;
00282   }
00283   if (is_nmethod_stub()) {
00284     std->print("Nmethod stub ");
00285     Disassembler::decode(jump_inst_addr(), state_addr());
00286     nmethod* nm = method();
00287     if (nm) {
00288       nm->key.print();
00289     } else {
00290       std->print_cr("{not pointing to nmethod}");
00291     }
00292     return;
00293   }
00294 
00295   if (is_block_closure_stub()) {
00296     std->print("Block closure stub");
00297     Disassembler::decode(jump_inst_addr(), state_addr());
00298     nmethod* nm = block_nmethod();
00299     if (nm) {
00300       nm->key.print();
00301     } else {
00302       std->print_cr("{not compiled yet}");
00303     }
00304     return;
00305   }
00306 
00307   if (is_link()) {
00308     std->print_cr("Link for:");
00309     jumpTable::jump_entry_for_at(link(), 0)->print();
00310     return;
00311   }
00312 
00313   fatal("unknown jump table entry");
00314 }
00315 
00316 void jumpTableEntry::report_verify_error(char* message) {
00317   error("jumpTableEntry %#x: %s", this, message);
00318 }
00319 
00320 void jumpTableEntry::verify() {
00321   if (is_unused()) {
00322     // Nothing to check in an unused entry
00323     return;
00324   }
00325 
00326   if (is_nmethod_stub()) {
00327     // Check nmethod
00328     char* addr = destination();
00329     if (!Universe::code->contains(addr)) report_verify_error("nmethod not in zone");
00330     if (method()->entryPoint() != addr)  report_verify_error("destination doesn't point to beginning of nmethod");
00331     return;
00332   }
00333 
00334   if (is_link()) {
00335     // Verify the elements in the list {nmethod} {block_closure}+
00336     jumpTableEntry* head = jumpTable::jump_entry_for_at(link(), 0);
00337     if (!head->is_nmethod_stub()) report_verify_error("must be nmethod stub");
00338     head->verify();
00339     nmethod* nm = method();
00340     if (!nm->has_noninlined_blocks()) report_verify_error("nmethod must have noninlined blocks");
00341     for (int index = 1; index <= nm->number_of_noninlined_blocks(); index++) {
00342        jumpTableEntry* son = jumpTable::jump_entry_for_at(link(), index);
00343        if (!son->is_block_closure_stub()) report_verify_error("must be block closure stub");
00344        son->verify();
00345     }
00346     return;
00347   }
00348 
00349   if (is_block_closure_stub()) {
00350     char* addr = destination();
00351     if (!Universe::code->contains(addr)) {
00352       if (addr != StubRoutines::compile_block_entry())
00353         report_verify_error("destination points neither into zone nor to compile stub");
00354     } else {
00355       nmethod* nm = block_nmethod();
00356       if (nm->entryPoint() != addr) 
00357         report_verify_error("destination doesn't point to beginning of nmethod");
00358     }
00359     return;
00360   }
00361 
00362   report_verify_error("invalid state");
00363 }
00364 
00365 void jumpTable::verify() {
00366 /*
00367   ResourceMark rm;
00368   int prev = -1;
00369   bool* check = NEW_RESOURCE_ARRAY(bool, n);
00370   for (int i = 0; i < n; i++) check[i] = false;
00371   for (int id = firstFree, j = 0; j < n - usedIDs; id = data[id], j++) {
00372     if (id < 0 || id >= n) {
00373       error("jumpTable: invalid ID %ld in free list (#%ld)\n", id, j);
00374     }
00375     if (check[id]) {
00376       error("jumpTable: loop with ID %ld in free list (#%ld)\n", id, j);
00377     }
00378     check[id] = true;
00379     prev = id;
00380   }
00381   if (id != n)
00382     error("jumpTable: wrong free list length, last = %ld, prev = %ld\n",
00383            id, prev);
00384 */
00385 }
00386 
00387 #endif

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