00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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