bool Relocator::expand_code_array(int delta) { int length = MAX2(code_length() + delta, code_length() * (100+code_slop_pct()) / 100); if (length > MAX_METHOD_LENGTH) { if (delta == 0 && code_length() <= MAX_METHOD_LENGTH) { length = MAX_METHOD_LENGTH; } else { return false; } } unsigned char* new_code_array = NEW_RESOURCE_ARRAY(unsigned char, length); if (!new_code_array) return false; // Expanding current array if (code_array() != NULL) { memcpy(new_code_array, code_array(), code_length()); } else { // Initial copy. Copy directly from methodOop memcpy(new_code_array, method()->code_base(), code_length()); } set_code_array(new_code_array); set_code_array_length(length); return true; }
// size is the new size of the instruction at bci. Hence, if size is less than the current // instruction sice, we will shrink the code. methodHandle Relocator::insert_space_at(int bci, int size, u_char inst_buffer[], TRAPS) { _changes = new GrowableArray<ChangeItem*> (10); _changes->push(new ChangeWiden(bci, size, inst_buffer)); if (TraceRelocator) { tty->print_cr("Space at: %d Size: %d", bci, size); _method->print(); _method->print_codes(); tty->print_cr("-------------------------------------------------"); } if (!handle_code_changes()) return methodHandle(); // Construct the new method methodHandle new_method = methodOopDesc::clone_with_new_data(method(), code_array(), code_length(), compressed_line_number_table(), compressed_line_number_table_size(), CHECK_(methodHandle())); set_method(new_method); if (TraceRelocator) { tty->print_cr("-------------------------------------------------"); tty->print_cr("new method"); _method->print_codes(); } return new_method; }
// size is the new size of the instruction at bci. Hence, if size is less than the current // instruction sice, we will shrink the code. methodHandle Relocator::insert_space_at(int bci, int size, u_char inst_buffer[], TRAPS) { _changes = new GrowableArray<ChangeItem*> (10); _changes->push(new ChangeWiden(bci, size, inst_buffer)); if (TraceRelocator) { tty->print_cr("Space at: %d Size: %d", bci, size); _method->print(); _method->print_codes(); tty->print_cr("-------------------------------------------------"); } if (!handle_code_changes()) return methodHandle(); // Construct the new method methodHandle new_method = Method::clone_with_new_data(method(), code_array(), code_length(), compressed_line_number_table(), compressed_line_number_table_size(), CHECK_(methodHandle())); // Deallocate the old Method* from metadata ClassLoaderData* loader_data = method()->method_holder()->class_loader_data(); loader_data->add_to_deallocate_list(method()()); set_method(new_method); if (TraceRelocator) { tty->print_cr("-------------------------------------------------"); tty->print_cr("new method"); _method->print_codes(); } return new_method; }
// The instruction at "bci", whose size is "ilen", is changing size by // "delta". Reallocate, move code, recalculate jumps, and enqueue // change items as necessary. bool Relocator::relocate_code(int bci, int ilen, int delta) { int next_bci = bci + ilen; if (delta > 0 && code_length() + delta > code_array_length()) { // Expand allocated code space, if necessary. if (!expand_code_array(delta)) { return false; } } // We require 4-byte alignment of code arrays. assert(((intptr_t)code_array() & 3) == 0, "check code alignment"); // Change jumps before doing the copying; this routine requires aligned switches. change_jumps(bci, delta); // In case we have shrunken a tableswitch/lookupswitch statement, we store the last // bytes that get overwritten. We have to copy the bytes after the change_jumps method // has been called, since it is likly to update last offset in a tableswitch/lookupswitch if (delta < 0) { assert(delta>=-3, "we cannot overwrite more than 3 bytes"); memcpy(_overwrite, addr_at(bci + ilen + delta), -delta); } memmove(addr_at(next_bci + delta), addr_at(next_bci), code_length() - next_bci); set_code_length(code_length() + delta); // Also adjust exception tables... adjust_exception_table(bci, delta); // Line number tables... adjust_line_no_table(bci, delta); // And local variable table... adjust_local_var_table(bci, delta); // Adjust stack maps adjust_stack_map_table(bci, delta); // Relocate the pending change stack... for (int j = 0; j < _changes->length(); j++) { ChangeItem* ci = _changes->at(j); ci->relocate(bci, delta); } // Notify any listeners about code relocation notify(bci, delta, code_length()); return true; }
int main(void) { // Runtime init checks if (sizeof(int32_t) != 4) { printf("Unexpected size of int32_t: %lu\n", sizeof(int32_t)); return 201; } code_malloc_init(); struct Expression *code; const vm_status load_result = load_expression(&code); log_trace("Total code size: %lu bytes.", code_length()); if (VM_OK == load_result) { print_value(stdout, code); printf("\n"); return 0; } else { log_error("Failed to load code, err: %i", load_result); /* PRINT_SIZE(struct string16); PRINT_SIZE(int32_t); PRINT_SIZE(int16_t); PRINT_SIZE(char); PRINT_SIZE(char*); PRINT_SIZE(struct Expression*); PRINT_SIZE(struct Expression); PRINT_SIZE(struct ExpressionList*); PRINT_SIZE(struct ExpressionList); PRINT_SIZE(value_t); */ return load_result; } }
static void write_code(struct oport *f, struct code *c) { u16 nbins, i; GCPRO2(f, c); nbins = code_length(c); if (c->varname) { write_string(f, prt_display, c->varname); pputs(": ", f); } pprintf(f, "Code["); write_string(f, prt_display, c->filename); pprintf(f, ":%u] %u bytes:\n", c->lineno, nbins); i = 0; while (i < nbins) i += write_instruction(f, c->ins + i, i); pprintf(f, "\n%u locals, %u stack\n", c->nb_locals, c->stkdepth); GCPOP(2); }
// Changes all jumps crossing "break_bci" by "delta". May enqueue things // on "rc->changes" void Relocator::change_jumps(int break_bci, int delta) { int bci = 0; Bytecodes::Code bc; // Now, adjust any affected instructions. while (bci < code_length()) { switch (bc= code_at(bci)) { case Bytecodes::_ifeq: case Bytecodes::_ifne: case Bytecodes::_iflt: case Bytecodes::_ifge: case Bytecodes::_ifgt: case Bytecodes::_ifle: case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: case Bytecodes::_goto: case Bytecodes::_jsr: change_jump(bci, bci+1, true, break_bci, delta); break; case Bytecodes::_goto_w: case Bytecodes::_jsr_w: change_jump(bci, bci+1, false, break_bci, delta); break; case Bytecodes::_tableswitch: case Bytecodes::_lookupswitch: case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { int recPad = get_orig_switch_pad(bci, (bc != Bytecodes::_tableswitch)); int oldPad = (recPad != -1) ? recPad : align(bci+1) - (bci+1); if (bci > break_bci) { int new_bci = bci + delta; int newPad = align(new_bci+1) - (new_bci+1); // Do we need to check the padding? if (newPad != oldPad) { if (recPad == -1) { _changes->push(new ChangeSwitchPad(bci, oldPad, (bc != Bytecodes::_tableswitch))); } } } // Then the rest, which depend on the kind of switch. switch (bc) { case Bytecodes::_tableswitch: { change_jump(bci, bci +1 + oldPad, false, break_bci, delta); // We cannot use the Bytecode_tableswitch abstraction, since the padding might not be correct. int lo = int_at(bci + 1 + oldPad + 4 * 1); int hi = int_at(bci + 1 + oldPad + 4 * 2); int n = hi - lo + 1; for (int k = 0; k < n; k++) { change_jump(bci, bci +1 + oldPad + 4*(k+3), false, break_bci, delta); } // Special next-bci calculation here... bci += 1 + oldPad + (n+3)*4; continue; } case Bytecodes::_lookupswitch: case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { change_jump(bci, bci +1 + oldPad, false, break_bci, delta); // We cannot use the Bytecode_lookupswitch abstraction, since the padding might not be correct. int npairs = int_at(bci + 1 + oldPad + 4 * 1); for (int k = 0; k < npairs; k++) { change_jump(bci, bci + 1 + oldPad + 4*(2 + 2*k + 1), false, break_bci, delta); } /* Special next-bci calculation here... */ bci += 1 + oldPad + (2 + (npairs*2))*4; continue; } default: ShouldNotReachHere(); } } default: break; } bci += rc_instr_len(bci); } }