// NOTE: %%%% if any change is made to this stub make sure that the function // pd_code_size_limit is changed to ensure the correct size for VtableStub VtableStub* VtableStubs::create_itable_stub(int itable_index) { const int sparc_code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(sparc_code_length) VtableStub(false, itable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), sparc_code_length); MacroAssembler* masm = new MacroAssembler(&cb); Register G3_Klass = G3_scratch; Register G5_icholder = G5; // Passed in as an argument Register G4_interface = G4_scratch; Label search; // Entry arguments: // G5_interface: Interface // O0: Receiver assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); __ load_klass(O0, G3_Klass); // Push a new window to get some temp registers. This chops the head of all // my 64-bit %o registers in the LION build, but this is OK because no longs // are passed in the %o registers. Instead, longs are passed in G1 and G4 // and so those registers are not available here. __ save(SP,-frame::register_save_words*wordSize,SP); #ifndef PRODUCT if (CountCompiledCalls) { __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), L0, L1); } #endif /* PRODUCT */ Label L_no_such_interface; Register L5_method = L5; // Receiver subtype check against REFC. __ ld_ptr(G5_icholder, CompiledICHolder::holder_klass_offset(), G4_interface); __ lookup_interface_method(// inputs: rec. class, interface, itable index G3_Klass, G4_interface, itable_index, // outputs: scan temp. reg1, scan temp. reg2 L5_method, L2, L3, L_no_such_interface, /*return_method=*/ false); // Get Method* and entrypoint for compiler __ ld_ptr(G5_icholder, CompiledICHolder::holder_metadata_offset(), G4_interface); __ lookup_interface_method(// inputs: rec. class, interface, itable index G3_Klass, G4_interface, itable_index, // outputs: method, scan temp. reg L5_method, L2, L3, L_no_such_interface); #ifndef PRODUCT if (DebugVtables) { Label L01; __ br_notnull_short(L5_method, Assembler::pt, L01); __ stop("Method* is null"); __ bind(L01); } #endif // If the following load is through a NULL pointer, we'll take an OS // exception that should translate into an AbstractMethodError. We need the // window count to be correct at that time. __ restore(L5_method, 0, G5_method); // Restore registers *before* the AME point. address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); // G5_method: Method* // O0: Receiver // G3_scratch: entry point __ JMP(G3_scratch, 0); __ delayed()->nop(); __ bind(L_no_such_interface); AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); __ jump_to(icce, G3_scratch); __ delayed()->restore(); masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", itable_index, s->entry_point(), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 2*BytesPerInstWord; // 32-bit offset is this much larger than a 13-bit one assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add"); s->set_exception_points(npe_addr, ame_addr); return s; }
const void *get_data_read() { uint32_t block_size; const void *data = get_data_read(&block_size); guarantee(block_size == lock_->cache()->max_block_size().value()); return data; }
~PlatformEvent() { guarantee(0, "invariant"); }
signal_t *write_acq_signal() { guarantee(!empty()); return current_page_acq()->write_acq_signal(); }
txn_t *txn() const { guarantee(!empty()); return txn_; }
// Write the field information portion of ClassFile structure // JVMSpec| u2 fields_count; // JVMSpec| field_info fields[fields_count]; void JvmtiClassFileReconstituter::write_field_infos() { HandleMark hm(thread()); typeArrayHandle fields(thread(), ikh()->fields()); int fields_length = fields->length(); int num_fields = fields_length / instanceKlass::next_offset; objArrayHandle fields_anno(thread(), ikh()->fields_annotations()); write_u2(num_fields); for (int index = 0; index < fields_length; index += instanceKlass::next_offset) { AccessFlags access_flags; int flags = fields->ushort_at(index + instanceKlass::access_flags_offset); access_flags.set_flags(flags); int name_index = fields->ushort_at(index + instanceKlass::name_index_offset); int signature_index = fields->ushort_at(index + instanceKlass::signature_index_offset); int initial_value_index = fields->ushort_at(index + instanceKlass::initval_index_offset); guarantee(name_index != 0 && signature_index != 0, "bad constant pool index for field"); int offset = ikh()->offset_from_fields( index ); int generic_signature_index = fields->ushort_at(index + instanceKlass::generic_signature_offset); typeArrayHandle anno(thread(), fields_anno.not_null() ? (typeArrayOop)(fields_anno->obj_at(index / instanceKlass::next_offset)) : (typeArrayOop)NULL); // JVMSpec| field_info { // JVMSpec| u2 access_flags; // JVMSpec| u2 name_index; // JVMSpec| u2 descriptor_index; // JVMSpec| u2 attributes_count; // JVMSpec| attribute_info attributes[attributes_count]; // JVMSpec| } write_u2(flags & JVM_RECOGNIZED_FIELD_MODIFIERS); write_u2(name_index); write_u2(signature_index); int attr_count = 0; if (initial_value_index != 0) { ++attr_count; } if (access_flags.is_synthetic()) { // ++attr_count; } if (generic_signature_index != 0) { ++attr_count; } if (anno.not_null()) { ++attr_count; // has RuntimeVisibleAnnotations attribute } write_u2(attr_count); if (initial_value_index != 0) { write_attribute_name_index("ConstantValue"); write_u4(2); //length always 2 write_u2(initial_value_index); } if (access_flags.is_synthetic()) { // write_synthetic_attribute(); } if (generic_signature_index != 0) { write_signature_attribute(generic_signature_index); } if (anno.not_null()) { write_annotations_attribute("RuntimeVisibleAnnotations", anno); } } }
access_t access() const { guarantee(!empty()); return current_page_acq()->access(); }
void G1BiasedMappedArrayBase::verify_biased_index_inclusive_end(idx_t biased_index) const { guarantee(_biased_base != NULL, "Array not initialized"); guarantee(biased_index >= bias() && biased_index <= (bias() + length()), err_msg("Biased index out of inclusive bounds, index: "SIZE_FORMAT" bias: "SIZE_FORMAT" length: "SIZE_FORMAT, biased_index, bias(), length())); }
void constMethodKlass::oop_verify_on(oop obj, outputStream* st) { Klass::oop_verify_on(obj, st); guarantee(obj->is_constMethod(), "object must be constMethod"); constMethodOop m = constMethodOop(obj); guarantee(m->is_perm(), "should be in permspace"); // Verification can occur during oop construction before the method or // other fields have been initialized. if (!obj->partially_loaded()) { guarantee(m->method()->is_perm(), "should be in permspace"); guarantee(m->method()->is_method(), "should be method"); typeArrayOop stackmap_data = m->stackmap_data(); guarantee(stackmap_data == NULL || stackmap_data->is_perm(), "should be in permspace"); guarantee(m->exception_table()->is_perm(), "should be in permspace"); guarantee(m->exception_table()->is_typeArray(), "should be type array"); address m_end = (address)((oop*) m + m->size()); address compressed_table_start = m->code_end(); guarantee(compressed_table_start <= m_end, "invalid method layout"); address compressed_table_end = compressed_table_start; // Verify line number table if (m->has_linenumber_table()) { CompressedLineNumberReadStream stream(m->compressed_linenumber_table()); while (stream.read_pair()) { guarantee(stream.bci() >= 0 && stream.bci() <= m->code_size(), "invalid bci in line number table"); } compressed_table_end += stream.position(); } guarantee(compressed_table_end <= m_end, "invalid method layout"); // Verify checked exceptions and local variable tables if (m->has_checked_exceptions()) { u2* addr = m->checked_exceptions_length_addr(); guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout"); } if (m->has_localvariable_table()) { u2* addr = m->localvariable_table_length_addr(); guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout"); } // Check compressed_table_end relative to uncompressed_table_start u2* uncompressed_table_start; if (m->has_localvariable_table()) { uncompressed_table_start = (u2*) m->localvariable_table_start(); } else { if (m->has_checked_exceptions()) { uncompressed_table_start = (u2*) m->checked_exceptions_start(); } else { uncompressed_table_start = (u2*) m_end; } } int gap = (intptr_t) uncompressed_table_start - (intptr_t) compressed_table_end; int max_gap = align_object_size(1)*BytesPerWord; guarantee(gap >= 0 && gap < max_gap, "invalid method layout"); } }
HEADER_DECLARE void Functor_set_arg(Term* term, functor_size_t n, Term* arg){ guarantee(term->type == FUNCTOR, "Functor_set_arg: not a functor"); guarantee(term->data.functor.size > n, "Functor_set_arg: too few arguments"); term->data.functor.args[n] = arg; }
void G1BiasedMappedArrayBase::verify_index(idx_t index) const { guarantee(_base != NULL, "Array not initialized"); guarantee(index < length(), err_msg("Index out of bounds index: "SIZE_FORMAT" length: "SIZE_FORMAT, index, length())); }
HeapWord* Space::object_iterate_careful_m(MemRegion mr, ObjectClosureCareful* cl) { guarantee(false, "NYI"); return bottom(); }
bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size, const NativeCallStack& stack, MEMFLAGS flag, bool all_committed) { assert(base_addr != NULL, "Invalid address"); assert(size > 0, "Invalid size"); assert(_reserved_regions != NULL, "Sanity check"); ReservedMemoryRegion rgn(base_addr, size, stack, flag); ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); LinkedListNode<ReservedMemoryRegion>* node; if (reserved_rgn == NULL) { VirtualMemorySummary::record_reserved_memory(size, flag); node = _reserved_regions->add(rgn); if (node != NULL) { node->data()->set_all_committed(all_committed); return true; } else { return false; } } else { if (reserved_rgn->same_region(base_addr, size)) { reserved_rgn->set_call_stack(stack); reserved_rgn->set_flag(flag); return true; } else if (reserved_rgn->adjacent_to(base_addr, size)) { VirtualMemorySummary::record_reserved_memory(size, flag); reserved_rgn->expand_region(base_addr, size); reserved_rgn->set_call_stack(stack); return true; } else { // Overlapped reservation. // It can happen when the regions are thread stacks, as JNI // thread does not detach from VM before exits, and leads to // leak JavaThread object if (reserved_rgn->flag() == mtThreadStack) { guarantee(!CheckJNICalls, "Attached JNI thread exited without being detached"); // Overwrite with new region // Release old region VirtualMemorySummary::record_uncommitted_memory(reserved_rgn->committed_size(), reserved_rgn->flag()); VirtualMemorySummary::record_released_memory(reserved_rgn->size(), reserved_rgn->flag()); // Add new region VirtualMemorySummary::record_reserved_memory(rgn.size(), flag); *reserved_rgn = rgn; return true; } // CDS mapping region. // CDS reserves the whole region for mapping CDS archive, then maps each section into the region. // NMT reports CDS as a whole. if (reserved_rgn->flag() == mtClassShared) { assert(reserved_rgn->contain_region(base_addr, size), "Reserved CDS region should contain this mapping region"); return true; } // Mapped CDS string region. // The string region(s) is part of the java heap. if (reserved_rgn->flag() == mtJavaHeap) { assert(reserved_rgn->contain_region(base_addr, size), "Reserved heap region should contain this mapping region"); return true; } ShouldNotReachHere(); return false; } } }
// Used by compiler only; may use only caller saved, non-argument registers // NOTE: %%%% if any change is made to this stub make sure that the function // pd_code_size_limit is changed to ensure the correct size for VtableStub VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int sparc_code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new(sparc_code_length) VtableStub(true, vtable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), sparc_code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), G5, G3_scratch); } #endif /* PRODUCT */ assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); // get receiver klass address npe_addr = __ pc(); __ load_klass(O0, G3_scratch); // set Method* (in case of interpreted method), and destination address #ifndef PRODUCT if (DebugVtables) { Label L; // check offset vs vtable length __ ld(G3_scratch, InstanceKlass::vtable_length_offset()*wordSize, G5); __ cmp_and_br_short(G5, vtable_index*vtableEntry::size(), Assembler::greaterUnsigned, Assembler::pt, L); __ set(vtable_index, O2); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), O0, O2); __ bind(L); } #endif __ lookup_virtual_method(G3_scratch, vtable_index, G5_method); #ifndef PRODUCT if (DebugVtables) { Label L; __ br_notnull_short(G5_method, Assembler::pt, L); __ stop("Vtable entry is ZERO"); __ bind(L); } #endif address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract // NOTE: for vtable dispatches, the vtable entry will never be null. __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); // jump to target (either compiled code or c2iadapter) __ JMP(G3_scratch, 0); // load Method* (in case we call c2iadapter) __ delayed()->nop(); masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", vtable_index, s->entry_point(), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 2*BytesPerInstWord; // 32-bit offset is this much larger than a 13-bit one assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add"); s->set_exception_points(npe_addr, ame_addr); return s; }
void ASPSYoungGen::resize_spaces(size_t requested_eden_size, size_t requested_survivor_size) { assert(UseAdaptiveSizePolicy, "sanity check"); assert(requested_eden_size > 0 && requested_survivor_size > 0, "just checking"); space_invariants(); // We require eden and to space to be empty if ((!eden_space()->is_empty()) || (!to_space()->is_empty())) { return; } if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr("PSYoungGen::resize_spaces(requested_eden_size: " SIZE_FORMAT ", requested_survivor_size: " SIZE_FORMAT ")", requested_eden_size, requested_survivor_size); gclog_or_tty->print_cr(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, eden_space()->bottom(), eden_space()->end(), pointer_delta(eden_space()->end(), eden_space()->bottom(), sizeof(char))); gclog_or_tty->print_cr(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, from_space()->bottom(), from_space()->end(), pointer_delta(from_space()->end(), from_space()->bottom(), sizeof(char))); gclog_or_tty->print_cr(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, to_space()->bottom(), to_space()->end(), pointer_delta( to_space()->end(), to_space()->bottom(), sizeof(char))); } // There's nothing to do if the new sizes are the same as the current if (requested_survivor_size == to_space()->capacity_in_bytes() && requested_survivor_size == from_space()->capacity_in_bytes() && requested_eden_size == eden_space()->capacity_in_bytes()) { if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" capacities are the right sizes, returning"); } return; } char* eden_start = (char*)virtual_space()->low(); char* eden_end = (char*)eden_space()->end(); char* from_start = (char*)from_space()->bottom(); char* from_end = (char*)from_space()->end(); char* to_start = (char*)to_space()->bottom(); char* to_end = (char*)to_space()->end(); assert(eden_start < from_start, "Cannot push into from_space"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); const size_t alignment = heap->intra_heap_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); bool eden_from_to_order = from_start < to_start; // Check whether from space is below to space if (eden_from_to_order) { // Eden, from, to if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" Eden, from, to:"); } // Set eden // "requested_eden_size" is a goal for the size of eden // and may not be attainable. "eden_size" below is // calculated based on the location of from-space and // the goal for the size of eden. from-space is // fixed in place because it contains live data. // The calculation is done this way to avoid 32bit // overflow (i.e., eden_start + requested_eden_size // may too large for representation in 32bits). size_t eden_size; if (maintain_minimum) { // Only make eden larger than the requested size if // the minimum size of the generation has to be maintained. // This could be done in general but policy at a higher // level is determining a requested size for eden and that // should be honored unless there is a fundamental reason. eden_size = pointer_delta(from_start, eden_start, sizeof(char)); } else { eden_size = MIN2(requested_eden_size, pointer_delta(from_start, eden_start, sizeof(char))); } eden_end = eden_start + eden_size; assert(eden_end >= eden_start, "addition overflowed") // To may resize into from space as long as it is clear of live data. // From space must remain page aligned, though, so we need to do some // extra calculations. // First calculate an optimal to-space to_end = (char*)virtual_space()->high(); to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size, sizeof(char)); // Does the optimal to-space overlap from-space? if (to_start < (char*)from_space()->end()) { assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from_space()->top(), from_start, sizeof(char)); // Should we be in this method if from_space is empty? Why not the set_space method? FIX ME! if (from_size == 0) { from_size = alignment; } else { from_size = align_size_up(from_size, alignment); } from_end = from_start + from_size; assert(from_end > from_start, "addition overflow or from_size problem"); guarantee(from_end <= (char*)from_space()->end(), "from_end moved to the right"); // Now update to_start with the new from_end to_start = MAX2(from_end, to_start); } guarantee(to_start != to_end, "to space is zero sized"); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" [eden_start .. eden_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, eden_start, eden_end, pointer_delta(eden_end, eden_start, sizeof(char))); gclog_or_tty->print_cr(" [from_start .. from_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, from_start, from_end, pointer_delta(from_end, from_start, sizeof(char))); gclog_or_tty->print_cr(" [ to_start .. to_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, to_start, to_end, pointer_delta( to_end, to_start, sizeof(char))); } } else { // Eden, to, from if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" Eden, to, from:"); } // To space gets priority over eden resizing. Note that we position // to space as if we were able to resize from space, even though from // space is not modified. // Giving eden priority was tried and gave poorer performance. to_end = (char*)pointer_delta(virtual_space()->high(), (char*)requested_survivor_size, sizeof(char)); to_end = MIN2(to_end, from_start); to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size, sizeof(char)); // if the space sizes are to be increased by several times then // 'to_start' will point beyond the young generation. In this case // 'to_start' should be adjusted. to_start = MAX2(to_start, eden_start + alignment); // Compute how big eden can be, then adjust end. // See comments above on calculating eden_end. size_t eden_size; if (maintain_minimum) { eden_size = pointer_delta(to_start, eden_start, sizeof(char)); } else { eden_size = MIN2(requested_eden_size, pointer_delta(to_start, eden_start, sizeof(char))); } eden_end = eden_start + eden_size; assert(eden_end >= eden_start, "addition overflowed") // Don't let eden shrink down to 0 or less. eden_end = MAX2(eden_end, eden_start + alignment); to_start = MAX2(to_start, eden_end); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" [eden_start .. eden_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, eden_start, eden_end, pointer_delta(eden_end, eden_start, sizeof(char))); gclog_or_tty->print_cr(" [ to_start .. to_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, to_start, to_end, pointer_delta( to_end, to_start, sizeof(char))); gclog_or_tty->print_cr(" [from_start .. from_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, from_start, from_end, pointer_delta(from_end, from_start, sizeof(char))); } } guarantee((HeapWord*)from_start <= from_space()->bottom(), "from start moved to the right"); guarantee((HeapWord*)from_end >= from_space()->top(), "from end moved into live data"); assert(is_object_aligned((intptr_t)eden_start), "checking alignment"); assert(is_object_aligned((intptr_t)from_start), "checking alignment"); assert(is_object_aligned((intptr_t)to_start), "checking alignment"); MemRegion edenMR((HeapWord*)eden_start, (HeapWord*)eden_end); MemRegion toMR ((HeapWord*)to_start, (HeapWord*)to_end); MemRegion fromMR((HeapWord*)from_start, (HeapWord*)from_end); // Let's make sure the call to initialize doesn't reset "top"! DEBUG_ONLY(HeapWord* old_from_top = from_space()->top();)
void PSYoungGen::space_invariants() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); const size_t alignment = heap->space_alignment(); // Currently, our eden size cannot shrink to zero guarantee(eden_space()->capacity_in_bytes() >= alignment, "eden too small"); guarantee(from_space()->capacity_in_bytes() >= alignment, "from too small"); guarantee(to_space()->capacity_in_bytes() >= alignment, "to too small"); // Relationship of spaces to each other char* eden_start = (char*)eden_space()->bottom(); char* eden_end = (char*)eden_space()->end(); char* from_start = (char*)from_space()->bottom(); char* from_end = (char*)from_space()->end(); char* to_start = (char*)to_space()->bottom(); char* to_end = (char*)to_space()->end(); guarantee(eden_start >= virtual_space()->low(), "eden bottom"); guarantee(eden_start < eden_end, "eden space consistency"); guarantee(from_start < from_end, "from space consistency"); guarantee(to_start < to_end, "to space consistency"); // Check whether from space is below to space if (from_start < to_start) { // Eden, from, to guarantee(eden_end <= from_start, "eden/from boundary"); guarantee(from_end <= to_start, "from/to boundary"); guarantee(to_end <= virtual_space()->high(), "to end"); } else { // Eden, to, from guarantee(eden_end <= to_start, "eden/to boundary"); guarantee(to_end <= from_start, "to/from boundary"); guarantee(from_end <= virtual_space()->high(), "from end"); } // More checks that the virtual space is consistent with the spaces assert(virtual_space()->committed_size() >= (eden_space()->capacity_in_bytes() + to_space()->capacity_in_bytes() + from_space()->capacity_in_bytes()), "Committed size is inconsistent"); assert(virtual_space()->committed_size() <= virtual_space()->reserved_size(), "Space invariant"); char* eden_top = (char*)eden_space()->top(); char* from_top = (char*)from_space()->top(); char* to_top = (char*)to_space()->top(); assert(eden_top <= virtual_space()->high(), "eden top"); assert(from_top <= virtual_space()->high(), "from top"); assert(to_top <= virtual_space()->high(), "to top"); virtual_space()->verify(); }
//------------------------------------------------------------------------------ // MethodHandles::generate_method_handle_stub // // Generate an "entry" field for a method handle. // This determines how the method handle will respond to calls. void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { // Here is the register state during an interpreted call, // as set up by generate_method_handle_interpreter_entry(): // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused) // - rcx: receiver method handle // - rax: method handle type (only used by the check_mtype entry point) // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) // - rdx: garbage temp, can blow away const Register rcx_recv = rcx; const Register rax_argslot = rax; const Register rbx_temp = rbx; const Register rdx_temp = rdx; // This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls) // and gen_c2i_adapter (from compiled calls): const Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi); // Argument registers for _raise_exception. // 32-bit: Pass first two oop/int args in registers ECX and EDX. const Register rarg0_code = LP64_ONLY(j_rarg0) NOT_LP64(rcx); const Register rarg1_actual = LP64_ONLY(j_rarg1) NOT_LP64(rdx); const Register rarg2_required = LP64_ONLY(j_rarg2) NOT_LP64(rdi); assert_different_registers(rarg0_code, rarg1_actual, rarg2_required, saved_last_sp); guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); // some handy addresses Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() ); Address rbx_method_fce( rbx, methodOopDesc::from_compiled_offset() ); Address rcx_mh_vmtarget( rcx_recv, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes() ); Address rcx_dmh_vmindex( rcx_recv, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes() ); Address rcx_bmh_vmargslot( rcx_recv, java_lang_invoke_BoundMethodHandle::vmargslot_offset_in_bytes() ); Address rcx_bmh_argument( rcx_recv, java_lang_invoke_BoundMethodHandle::argument_offset_in_bytes() ); Address rcx_amh_vmargslot( rcx_recv, java_lang_invoke_AdapterMethodHandle::vmargslot_offset_in_bytes() ); Address rcx_amh_argument( rcx_recv, java_lang_invoke_AdapterMethodHandle::argument_offset_in_bytes() ); Address rcx_amh_conversion( rcx_recv, java_lang_invoke_AdapterMethodHandle::conversion_offset_in_bytes() ); Address vmarg; // __ argument_address(vmargslot) const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes(); if (have_entry(ek)) { __ nop(); // empty stubs make SG sick return; } address interp_entry = __ pc(); trace_method_handle(_masm, entry_name(ek)); BLOCK_COMMENT(entry_name(ek)); switch ((int) ek) { case _raise_exception: { // Not a real MH entry, but rather shared code for raising an // exception. Since we use the compiled entry, arguments are // expected in compiler argument registers. assert(raise_exception_method(), "must be set"); assert(raise_exception_method()->from_compiled_entry(), "method must be linked"); const Register rdi_pc = rax; __ pop(rdi_pc); // caller PC __ mov(rsp, saved_last_sp); // cut the stack back to where the caller started Register rbx_method = rbx_temp; Label L_no_method; // FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); __ testptr(rbx_method, rbx_method); __ jccb(Assembler::zero, L_no_method); const int jobject_oop_offset = 0; __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject __ testptr(rbx_method, rbx_method); __ jccb(Assembler::zero, L_no_method); __ verify_oop(rbx_method); NOT_LP64(__ push(rarg2_required)); __ push(rdi_pc); // restore caller PC __ jmp(rbx_method_fce); // jump to compiled entry // Do something that is at least causes a valid throw from the interpreter. __ bind(L_no_method); __ push(rarg2_required); __ push(rarg1_actual); __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); } break; case _invokestatic_mh: case _invokespecial_mh: { Register rbx_method = rbx_temp; __ load_heap_oop(rbx_method, rcx_mh_vmtarget); // target is a methodOop __ verify_oop(rbx_method); // same as TemplateTable::invokestatic or invokespecial, // minus the CP setup and profiling: if (ek == _invokespecial_mh) { // Must load & check the first argument before entering the target method. __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp); __ movptr(rcx_recv, __ argument_address(rax_argslot, -1)); __ null_check(rcx_recv); __ verify_oop(rcx_recv); } __ jmp(rbx_method_fie); } break; case _invokevirtual_mh: { // same as TemplateTable::invokevirtual, // minus the CP setup and profiling: // pick out the vtable index and receiver offset from the MH, // and then we can discard it: __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp); Register rbx_index = rbx_temp; __ movl(rbx_index, rcx_dmh_vmindex); // Note: The verifier allows us to ignore rcx_mh_vmtarget. __ movptr(rcx_recv, __ argument_address(rax_argslot, -1)); __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes()); // get receiver klass Register rax_klass = rax_argslot; __ load_klass(rax_klass, rcx_recv); __ verify_oop(rax_klass); // get target methodOop & entry point const int base = instanceKlass::vtable_start_offset() * wordSize; assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); Address vtable_entry_addr(rax_klass, rbx_index, Address::times_ptr, base + vtableEntry::method_offset_in_bytes()); Register rbx_method = rbx_temp; __ movptr(rbx_method, vtable_entry_addr); __ verify_oop(rbx_method); __ jmp(rbx_method_fie); } break; case _invokeinterface_mh: { // same as TemplateTable::invokeinterface, // minus the CP setup and profiling: // pick out the interface and itable index from the MH. __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp); Register rdx_intf = rdx_temp; Register rbx_index = rbx_temp; __ load_heap_oop(rdx_intf, rcx_mh_vmtarget); __ movl(rbx_index, rcx_dmh_vmindex); __ movptr(rcx_recv, __ argument_address(rax_argslot, -1)); __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes()); // get receiver klass Register rax_klass = rax_argslot; __ load_klass(rax_klass, rcx_recv); __ verify_oop(rax_klass); Register rdi_temp = rdi; Register rbx_method = rbx_index; // get interface klass Label no_such_interface; __ verify_oop(rdx_intf); __ lookup_interface_method(rax_klass, rdx_intf, // note: next two args must be the same: rbx_index, rbx_method, rdi_temp, no_such_interface); __ verify_oop(rbx_method); __ jmp(rbx_method_fie); __ hlt(); __ bind(no_such_interface); // Throw an exception. // For historical reasons, it will be IncompatibleClassChangeError. __ mov(rbx_temp, rcx_recv); // rarg2_required might be RCX assert_different_registers(rarg2_required, rbx_temp); __ movptr(rarg2_required, Address(rdx_intf, java_mirror_offset)); // required interface __ mov( rarg1_actual, rbx_temp); // bad receiver __ movl( rarg0_code, (int) Bytecodes::_invokeinterface); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); } break; case _bound_ref_mh: case _bound_int_mh: case _bound_long_mh: case _bound_ref_direct_mh: case _bound_int_direct_mh: case _bound_long_direct_mh: { bool direct_to_method = (ek >= _bound_ref_direct_mh); BasicType arg_type = T_ILLEGAL; int arg_mask = _INSERT_NO_MASK; int arg_slots = -1; get_ek_bound_mh_info(ek, arg_type, arg_mask, arg_slots); // make room for the new argument: __ movl(rax_argslot, rcx_bmh_vmargslot); __ lea(rax_argslot, __ argument_address(rax_argslot)); insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask, rax_argslot, rbx_temp, rdx_temp); // store bound argument into the new stack slot: __ load_heap_oop(rbx_temp, rcx_bmh_argument); if (arg_type == T_OBJECT) { __ movptr(Address(rax_argslot, 0), rbx_temp); } else { Address prim_value_addr(rbx_temp, java_lang_boxing_object::value_offset_in_bytes(arg_type)); const int arg_size = type2aelembytes(arg_type); __ load_sized_value(rdx_temp, prim_value_addr, arg_size, is_signed_subword_type(arg_type), rbx_temp); __ store_sized_value(Address(rax_argslot, 0), rdx_temp, arg_size, rbx_temp); } if (direct_to_method) { Register rbx_method = rbx_temp; __ load_heap_oop(rbx_method, rcx_mh_vmtarget); __ verify_oop(rbx_method); __ jmp(rbx_method_fie); } else { __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ verify_oop(rcx_recv); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } } break; case _adapter_retype_only: case _adapter_retype_raw: // immediately jump to the next MH layer: __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ verify_oop(rcx_recv); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); // This is OK when all parameter types widen. // It is also OK when a return type narrows. break; case _adapter_check_cast: { // temps: Register rbx_klass = rbx_temp; // interesting AMH data // check a reference argument before jumping to the next layer of MH: __ movl(rax_argslot, rcx_amh_vmargslot); vmarg = __ argument_address(rax_argslot); // What class are we casting to? __ load_heap_oop(rbx_klass, rcx_amh_argument); // this is a Class object! __ load_heap_oop(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes())); Label done; __ movptr(rdx_temp, vmarg); __ testptr(rdx_temp, rdx_temp); __ jcc(Assembler::zero, done); // no cast if null __ load_klass(rdx_temp, rdx_temp); // live at this point: // - rbx_klass: klass required by the target method // - rdx_temp: argument klass to test // - rcx_recv: adapter method handle __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done); // If we get here, the type check failed! // Call the wrong_method_type stub, passing the failing argument type in rax. Register rax_mtype = rax_argslot; __ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field __ movptr(rdx_temp, vmarg); assert_different_registers(rarg2_required, rdx_temp); __ load_heap_oop(rarg2_required, rcx_amh_argument); // required class __ mov( rarg1_actual, rdx_temp); // bad object __ movl( rarg0_code, (int) Bytecodes::_checkcast); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ bind(done); // get the new MH: __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_prim_to_prim: case _adapter_ref_to_prim: // handled completely by optimized cases __ stop("init_AdapterMethodHandle should not issue this"); break; case _adapter_opt_i2i: // optimized subcase of adapt_prim_to_prim //case _adapter_opt_f2i: // optimized subcase of adapt_prim_to_prim case _adapter_opt_l2i: // optimized subcase of adapt_prim_to_prim case _adapter_opt_unboxi: // optimized subcase of adapt_ref_to_prim { // perform an in-place conversion to int or an int subword __ movl(rax_argslot, rcx_amh_vmargslot); vmarg = __ argument_address(rax_argslot); switch (ek) { case _adapter_opt_i2i: __ movl(rdx_temp, vmarg); break; case _adapter_opt_l2i: { // just delete the extra slot; on a little-endian machine we keep the first __ lea(rax_argslot, __ argument_address(rax_argslot, 1)); remove_arg_slots(_masm, -stack_move_unit(), rax_argslot, rbx_temp, rdx_temp); vmarg = Address(rax_argslot, -Interpreter::stackElementSize); __ movl(rdx_temp, vmarg); } break; case _adapter_opt_unboxi: { // Load the value up from the heap. __ movptr(rdx_temp, vmarg); int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT); #ifdef ASSERT for (int bt = T_BOOLEAN; bt < T_INT; bt++) { if (is_subword_type(BasicType(bt))) assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), ""); } #endif __ null_check(rdx_temp, value_offset); __ movl(rdx_temp, Address(rdx_temp, value_offset)); // We load this as a word. Because we are little-endian, // the low bits will be correct, but the high bits may need cleaning. // The vminfo will guide us to clean those bits. } break; default: ShouldNotReachHere(); } // Do the requested conversion and store the value. Register rbx_vminfo = rbx_temp; __ movl(rbx_vminfo, rcx_amh_conversion); assert(CONV_VMINFO_SHIFT == 0, "preshifted"); // get the new MH: __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); // (now we are done with the old MH) // original 32-bit vmdata word must be of this form: // | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | __ xchgptr(rcx, rbx_vminfo); // free rcx for shifts __ shll(rdx_temp /*, rcx*/); Label zero_extend, done; __ testl(rcx, CONV_VMINFO_SIGN_FLAG); __ jccb(Assembler::zero, zero_extend); // this path is taken for int->byte, int->short __ sarl(rdx_temp /*, rcx*/); __ jmpb(done); __ bind(zero_extend); // this is taken for int->char __ shrl(rdx_temp /*, rcx*/); __ bind(done); __ movl(vmarg, rdx_temp); // Store the value. __ xchgptr(rcx, rbx_vminfo); // restore rcx_recv __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim case _adapter_opt_unboxl: // optimized subcase of adapt_ref_to_prim { // perform an in-place int-to-long or ref-to-long conversion __ movl(rax_argslot, rcx_amh_vmargslot); // on a little-endian machine we keep the first slot and add another after __ lea(rax_argslot, __ argument_address(rax_argslot, 1)); insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK, rax_argslot, rbx_temp, rdx_temp); Address vmarg1(rax_argslot, -Interpreter::stackElementSize); Address vmarg2 = vmarg1.plus_disp(Interpreter::stackElementSize); switch (ek) { case _adapter_opt_i2l: { #ifdef _LP64 __ movslq(rdx_temp, vmarg1); // Load sign-extended __ movq(vmarg1, rdx_temp); // Store into first slot #else __ movl(rdx_temp, vmarg1); __ sarl(rdx_temp, BitsPerInt - 1); // __ extend_sign() __ movl(vmarg2, rdx_temp); // store second word #endif } break; case _adapter_opt_unboxl: { // Load the value up from the heap. __ movptr(rdx_temp, vmarg1); int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG); assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), ""); __ null_check(rdx_temp, value_offset); #ifdef _LP64 __ movq(rbx_temp, Address(rdx_temp, value_offset)); __ movq(vmarg1, rbx_temp); #else __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt)); __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt)); __ movl(vmarg1, rbx_temp); __ movl(vmarg2, rdx_temp); #endif } break; default: ShouldNotReachHere(); } __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_opt_f2d: // optimized subcase of adapt_prim_to_prim case _adapter_opt_d2f: // optimized subcase of adapt_prim_to_prim { // perform an in-place floating primitive conversion __ movl(rax_argslot, rcx_amh_vmargslot); __ lea(rax_argslot, __ argument_address(rax_argslot, 1)); if (ek == _adapter_opt_f2d) { insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK, rax_argslot, rbx_temp, rdx_temp); } Address vmarg(rax_argslot, -Interpreter::stackElementSize); #ifdef _LP64 if (ek == _adapter_opt_f2d) { __ movflt(xmm0, vmarg); __ cvtss2sd(xmm0, xmm0); __ movdbl(vmarg, xmm0); } else { __ movdbl(xmm0, vmarg); __ cvtsd2ss(xmm0, xmm0); __ movflt(vmarg, xmm0); } #else //_LP64 if (ek == _adapter_opt_f2d) { __ fld_s(vmarg); // load float to ST0 __ fstp_s(vmarg); // store single } else { __ fld_d(vmarg); // load double to ST0 __ fstp_s(vmarg); // store single } #endif //_LP64 if (ek == _adapter_opt_d2f) { remove_arg_slots(_masm, -stack_move_unit(), rax_argslot, rbx_temp, rdx_temp); } __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_prim_to_ref: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI break; case _adapter_swap_args: case _adapter_rot_args: // handled completely by optimized cases __ stop("init_AdapterMethodHandle should not issue this"); break; case _adapter_opt_swap_1: case _adapter_opt_swap_2: case _adapter_opt_rot_1_up: case _adapter_opt_rot_1_down: case _adapter_opt_rot_2_up: case _adapter_opt_rot_2_down: { int swap_bytes = 0, rotate = 0; get_ek_adapter_opt_swap_rot_info(ek, swap_bytes, rotate); // 'argslot' is the position of the first argument to swap __ movl(rax_argslot, rcx_amh_vmargslot); __ lea(rax_argslot, __ argument_address(rax_argslot)); // 'vminfo' is the second Register rbx_destslot = rbx_temp; __ movl(rbx_destslot, rcx_amh_conversion); assert(CONV_VMINFO_SHIFT == 0, "preshifted"); __ andl(rbx_destslot, CONV_VMINFO_MASK); __ lea(rbx_destslot, __ argument_address(rbx_destslot)); DEBUG_ONLY(verify_argslot(_masm, rbx_destslot, "swap point must fall within current frame")); if (!rotate) { for (int i = 0; i < swap_bytes; i += wordSize) { __ movptr(rdx_temp, Address(rax_argslot , i)); __ push(rdx_temp); __ movptr(rdx_temp, Address(rbx_destslot, i)); __ movptr(Address(rax_argslot, i), rdx_temp); __ pop(rdx_temp); __ movptr(Address(rbx_destslot, i), rdx_temp); } } else { // push the first chunk, which is going to get overwritten for (int i = swap_bytes; (i -= wordSize) >= 0; ) { __ movptr(rdx_temp, Address(rax_argslot, i)); __ push(rdx_temp); } if (rotate > 0) { // rotate upward __ subptr(rax_argslot, swap_bytes); #ifdef ASSERT { // Verify that argslot > destslot, by at least swap_bytes. Label L_ok; __ cmpptr(rax_argslot, rbx_destslot); __ jccb(Assembler::aboveEqual, L_ok); __ stop("source must be above destination (upward rotation)"); __ bind(L_ok); } #endif // work argslot down to destslot, copying contiguous data upwards // pseudo-code: // rax = src_addr - swap_bytes // rbx = dest_addr // while (rax >= rbx) *(rax + swap_bytes) = *(rax + 0), rax--; Label loop; __ bind(loop); __ movptr(rdx_temp, Address(rax_argslot, 0)); __ movptr(Address(rax_argslot, swap_bytes), rdx_temp); __ addptr(rax_argslot, -wordSize); __ cmpptr(rax_argslot, rbx_destslot); __ jccb(Assembler::aboveEqual, loop); } else { __ addptr(rax_argslot, swap_bytes); #ifdef ASSERT { // Verify that argslot < destslot, by at least swap_bytes. Label L_ok; __ cmpptr(rax_argslot, rbx_destslot); __ jccb(Assembler::belowEqual, L_ok); __ stop("source must be below destination (downward rotation)"); __ bind(L_ok); } #endif // work argslot up to destslot, copying contiguous data downwards // pseudo-code: // rax = src_addr + swap_bytes // rbx = dest_addr // while (rax <= rbx) *(rax - swap_bytes) = *(rax + 0), rax++; Label loop; __ bind(loop); __ movptr(rdx_temp, Address(rax_argslot, 0)); __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp); __ addptr(rax_argslot, wordSize); __ cmpptr(rax_argslot, rbx_destslot); __ jccb(Assembler::belowEqual, loop); } // pop the original first chunk into the destination slot, now free for (int i = 0; i < swap_bytes; i += wordSize) { __ pop(rdx_temp); __ movptr(Address(rbx_destslot, i), rdx_temp); } } __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_dup_args: { // 'argslot' is the position of the first argument to duplicate __ movl(rax_argslot, rcx_amh_vmargslot); __ lea(rax_argslot, __ argument_address(rax_argslot)); // 'stack_move' is negative number of words to duplicate Register rdx_stack_move = rdx_temp; __ movl2ptr(rdx_stack_move, rcx_amh_conversion); __ sarptr(rdx_stack_move, CONV_STACK_MOVE_SHIFT); int argslot0_num = 0; Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num)); assert(argslot0.base() == rsp, ""); int pre_arg_size = argslot0.disp(); assert(pre_arg_size % wordSize == 0, ""); assert(pre_arg_size > 0, "must include PC"); // remember the old rsp+1 (argslot[0]) Register rbx_oldarg = rbx_temp; __ lea(rbx_oldarg, argslot0); // move rsp down to make room for dups __ lea(rsp, Address(rsp, rdx_stack_move, Address::times_ptr)); // compute the new rsp+1 (argslot[0]) Register rdx_newarg = rdx_temp; __ lea(rdx_newarg, argslot0); __ push(rdi); // need a temp // (preceding push must be done after arg addresses are taken!) // pull down the pre_arg_size data (PC) for (int i = -pre_arg_size; i < 0; i += wordSize) { __ movptr(rdi, Address(rbx_oldarg, i)); __ movptr(Address(rdx_newarg, i), rdi); } // copy from rax_argslot[0...] down to new_rsp[1...] // pseudo-code: // rbx = old_rsp+1 // rdx = new_rsp+1 // rax = argslot // while (rdx < rbx) *rdx++ = *rax++ Label loop; __ bind(loop); __ movptr(rdi, Address(rax_argslot, 0)); __ movptr(Address(rdx_newarg, 0), rdi); __ addptr(rax_argslot, wordSize); __ addptr(rdx_newarg, wordSize); __ cmpptr(rdx_newarg, rbx_oldarg); __ jccb(Assembler::less, loop); __ pop(rdi); // restore temp __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_drop_args: { // 'argslot' is the position of the first argument to nuke __ movl(rax_argslot, rcx_amh_vmargslot); __ lea(rax_argslot, __ argument_address(rax_argslot)); __ push(rdi); // need a temp // (must do previous push after argslot address is taken) // 'stack_move' is number of words to drop Register rdi_stack_move = rdi; __ movl2ptr(rdi_stack_move, rcx_amh_conversion); __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); remove_arg_slots(_masm, rdi_stack_move, rax_argslot, rbx_temp, rdx_temp); __ pop(rdi); // restore temp __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } break; case _adapter_collect_args: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI break; case _adapter_spread_args: // handled completely by optimized cases __ stop("init_AdapterMethodHandle should not issue this"); break; case _adapter_opt_spread_0: case _adapter_opt_spread_1: case _adapter_opt_spread_more: { // spread an array out into a group of arguments int length_constant = get_ek_adapter_opt_spread_info(ek); // find the address of the array argument __ movl(rax_argslot, rcx_amh_vmargslot); __ lea(rax_argslot, __ argument_address(rax_argslot)); // grab some temps { __ push(rsi); __ push(rdi); } // (preceding pushes must be done after argslot address is taken!) #define UNPUSH_RSI_RDI \ { __ pop(rdi); __ pop(rsi); } // arx_argslot points both to the array and to the first output arg vmarg = Address(rax_argslot, 0); // Get the array value. Register rsi_array = rsi; Register rdx_array_klass = rdx_temp; BasicType elem_type = T_OBJECT; int length_offset = arrayOopDesc::length_offset_in_bytes(); int elem0_offset = arrayOopDesc::base_offset_in_bytes(elem_type); __ movptr(rsi_array, vmarg); Label skip_array_check; if (length_constant == 0) { __ testptr(rsi_array, rsi_array); __ jcc(Assembler::zero, skip_array_check); } __ null_check(rsi_array, oopDesc::klass_offset_in_bytes()); __ load_klass(rdx_array_klass, rsi_array); // Check the array type. Register rbx_klass = rbx_temp; __ load_heap_oop(rbx_klass, rcx_amh_argument); // this is a Class object! __ load_heap_oop(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes())); Label ok_array_klass, bad_array_klass, bad_array_length; __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi, ok_array_klass); // If we get here, the type check failed! __ jmp(bad_array_klass); __ bind(ok_array_klass); // Check length. if (length_constant >= 0) { __ cmpl(Address(rsi_array, length_offset), length_constant); } else { Register rbx_vminfo = rbx_temp; __ movl(rbx_vminfo, rcx_amh_conversion); assert(CONV_VMINFO_SHIFT == 0, "preshifted"); __ andl(rbx_vminfo, CONV_VMINFO_MASK); __ cmpl(rbx_vminfo, Address(rsi_array, length_offset)); } __ jcc(Assembler::notEqual, bad_array_length); Register rdx_argslot_limit = rdx_temp; // Array length checks out. Now insert any required stack slots. if (length_constant == -1) { // Form a pointer to the end of the affected region. __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize)); // 'stack_move' is negative number of words to insert Register rdi_stack_move = rdi; __ movl2ptr(rdi_stack_move, rcx_amh_conversion); __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); Register rsi_temp = rsi_array; // spill this insert_arg_slots(_masm, rdi_stack_move, -1, rax_argslot, rbx_temp, rsi_temp); // reload the array (since rsi was killed) __ movptr(rsi_array, vmarg); } else if (length_constant > 1) { int arg_mask = 0; int new_slots = (length_constant - 1); for (int i = 0; i < new_slots; i++) { arg_mask <<= 1; arg_mask |= _INSERT_REF_MASK; } insert_arg_slots(_masm, new_slots * stack_move_unit(), arg_mask, rax_argslot, rbx_temp, rdx_temp); } else if (length_constant == 1) { // no stack resizing required } else if (length_constant == 0) { remove_arg_slots(_masm, -stack_move_unit(), rax_argslot, rbx_temp, rdx_temp); } // Copy from the array to the new slots. // Note: Stack change code preserves integrity of rax_argslot pointer. // So even after slot insertions, rax_argslot still points to first argument. if (length_constant == -1) { // [rax_argslot, rdx_argslot_limit) is the area we are inserting into. Register rsi_source = rsi_array; __ lea(rsi_source, Address(rsi_array, elem0_offset)); Label loop; __ bind(loop); __ movptr(rbx_temp, Address(rsi_source, 0)); __ movptr(Address(rax_argslot, 0), rbx_temp); __ addptr(rsi_source, type2aelembytes(elem_type)); __ addptr(rax_argslot, Interpreter::stackElementSize); __ cmpptr(rax_argslot, rdx_argslot_limit); __ jccb(Assembler::less, loop); } else if (length_constant == 0) { __ bind(skip_array_check); // nothing to copy } else { int elem_offset = elem0_offset; int slot_offset = 0; for (int index = 0; index < length_constant; index++) { __ movptr(rbx_temp, Address(rsi_array, elem_offset)); __ movptr(Address(rax_argslot, slot_offset), rbx_temp); elem_offset += type2aelembytes(elem_type); slot_offset += Interpreter::stackElementSize; } } // Arguments are spread. Move to next method handle. UNPUSH_RSI_RDI; __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ jump_to_method_handle_entry(rcx_recv, rdx_temp); __ bind(bad_array_klass); UNPUSH_RSI_RDI; assert(!vmarg.uses(rarg2_required), "must be different registers"); __ movptr(rarg2_required, Address(rdx_array_klass, java_mirror_offset)); // required type __ movptr(rarg1_actual, vmarg); // bad array __ movl( rarg0_code, (int) Bytecodes::_aaload); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ bind(bad_array_length); UNPUSH_RSI_RDI; assert(!vmarg.uses(rarg2_required), "must be different registers"); __ mov (rarg2_required, rcx_recv); // AMH requiring a certain length __ movptr(rarg1_actual, vmarg); // bad array __ movl( rarg0_code, (int) Bytecodes::_arraylength); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); #undef UNPUSH_RSI_RDI } break; case _adapter_flyby: case _adapter_ricochet: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI break; default: ShouldNotReachHere(); } __ hlt(); address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry); __ unimplemented(entry_name(ek)); // %%% FIXME: NYI init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie)); }
bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) { const size_t alignment = virtual_space()->alignment(); size_t orig_size = virtual_space()->committed_size(); bool size_changed = false; // There used to be this guarantee there. // guarantee ((eden_size + 2*survivor_size) <= _max_gen_size, "incorrect input arguments"); // Code below forces this requirement. In addition the desired eden // size and desired survivor sizes are desired goals and may // exceed the total generation size. assert(min_gen_size() <= orig_size && orig_size <= max_size(), "just checking"); // Adjust new generation size const size_t eden_plus_survivors = align_size_up(eden_size + 2 * survivor_size, alignment); size_t desired_size = MAX2(MIN2(eden_plus_survivors, max_size()), min_gen_size()); assert(desired_size <= max_size(), "just checking"); if (desired_size > orig_size) { // Grow the generation size_t change = desired_size - orig_size; assert(change % alignment == 0, "just checking"); HeapWord* prev_high = (HeapWord*) virtual_space()->high(); if (!virtual_space()->expand_by(change)) { return false; // Error if we fail to resize! } if (ZapUnusedHeapArea) { // Mangle newly committed space immediately because it // can be done here more simply that after the new // spaces have been computed. HeapWord* new_high = (HeapWord*) virtual_space()->high(); MemRegion mangle_region(prev_high, new_high); SpaceMangler::mangle_region(mangle_region); } size_changed = true; } else if (desired_size < orig_size) { size_t desired_change = orig_size - desired_size; assert(desired_change % alignment == 0, "just checking"); desired_change = limit_gen_shrink(desired_change); if (desired_change > 0) { virtual_space()->shrink_by(desired_change); reset_survivors_after_shrink(); size_changed = true; } } else { if (Verbose && PrintGC) { if (orig_size == gen_size_limit()) { gclog_or_tty->print_cr("PSYoung generation size at maximum: " SIZE_FORMAT "K", orig_size/K); } else if (orig_size == min_gen_size()) { gclog_or_tty->print_cr("PSYoung generation size at minium: " SIZE_FORMAT "K", orig_size/K); } } } if (size_changed) { post_resize(); if (Verbose && PrintGC) { size_t current_size = virtual_space()->committed_size(); gclog_or_tty->print_cr("PSYoung generation size changed: " SIZE_FORMAT "K->" SIZE_FORMAT "K", orig_size/K, current_size/K); } } guarantee(eden_plus_survivors <= virtual_space()->committed_size() || virtual_space()->committed_size() == max_size(), "Sanity"); return true; }
block_id_t block_id() const { guarantee(txn_ != nullptr); return current_page_acq()->block_id(); }
void PSYoungGen::resize_spaces(size_t requested_eden_size, size_t requested_survivor_size) { assert(UseAdaptiveSizePolicy, "sanity check"); assert(requested_eden_size > 0 && requested_survivor_size > 0, "just checking"); // We require eden and to space to be empty if ((!eden_space()->is_empty()) || (!to_space()->is_empty())) { return; } if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr("PSYoungGen::resize_spaces(requested_eden_size: " SIZE_FORMAT ", requested_survivor_size: " SIZE_FORMAT ")", requested_eden_size, requested_survivor_size); gclog_or_tty->print_cr(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, eden_space()->bottom(), eden_space()->end(), pointer_delta(eden_space()->end(), eden_space()->bottom(), sizeof(char))); gclog_or_tty->print_cr(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, from_space()->bottom(), from_space()->end(), pointer_delta(from_space()->end(), from_space()->bottom(), sizeof(char))); gclog_or_tty->print_cr(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, to_space()->bottom(), to_space()->end(), pointer_delta( to_space()->end(), to_space()->bottom(), sizeof(char))); } // There's nothing to do if the new sizes are the same as the current if (requested_survivor_size == to_space()->capacity_in_bytes() && requested_survivor_size == from_space()->capacity_in_bytes() && requested_eden_size == eden_space()->capacity_in_bytes()) { if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" capacities are the right sizes, returning"); } return; } char* eden_start = (char*)eden_space()->bottom(); char* eden_end = (char*)eden_space()->end(); char* from_start = (char*)from_space()->bottom(); char* from_end = (char*)from_space()->end(); char* to_start = (char*)to_space()->bottom(); char* to_end = (char*)to_space()->end(); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); bool eden_from_to_order = from_start < to_start; // Check whether from space is below to space if (eden_from_to_order) { // Eden, from, to eden_from_to_order = true; if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" Eden, from, to:"); } // Set eden // "requested_eden_size" is a goal for the size of eden // and may not be attainable. "eden_size" below is // calculated based on the location of from-space and // the goal for the size of eden. from-space is // fixed in place because it contains live data. // The calculation is done this way to avoid 32bit // overflow (i.e., eden_start + requested_eden_size // may too large for representation in 32bits). size_t eden_size; if (maintain_minimum) { // Only make eden larger than the requested size if // the minimum size of the generation has to be maintained. // This could be done in general but policy at a higher // level is determining a requested size for eden and that // should be honored unless there is a fundamental reason. eden_size = pointer_delta(from_start, eden_start, sizeof(char)); } else { eden_size = MIN2(requested_eden_size, pointer_delta(from_start, eden_start, sizeof(char))); } eden_end = eden_start + eden_size; assert(eden_end >= eden_start, "addition overflowed"); // To may resize into from space as long as it is clear of live data. // From space must remain page aligned, though, so we need to do some // extra calculations. // First calculate an optimal to-space to_end = (char*)virtual_space()->high(); to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size, sizeof(char)); // Does the optimal to-space overlap from-space? if (to_start < (char*)from_space()->end()) { assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from_space()->top(), from_start, sizeof(char)); // Should we be in this method if from_space is empty? Why not the set_space method? FIX ME! if (from_size == 0) { from_size = alignment; } else { from_size = align_size_up(from_size, alignment); } from_end = from_start + from_size; assert(from_end > from_start, "addition overflow or from_size problem"); guarantee(from_end <= (char*)from_space()->end(), "from_end moved to the right"); // Now update to_start with the new from_end to_start = MAX2(from_end, to_start); } guarantee(to_start != to_end, "to space is zero sized"); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" [eden_start .. eden_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, eden_start, eden_end, pointer_delta(eden_end, eden_start, sizeof(char))); gclog_or_tty->print_cr(" [from_start .. from_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, from_start, from_end, pointer_delta(from_end, from_start, sizeof(char))); gclog_or_tty->print_cr(" [ to_start .. to_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, to_start, to_end, pointer_delta( to_end, to_start, sizeof(char))); } } else { // Eden, to, from if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" Eden, to, from:"); } // To space gets priority over eden resizing. Note that we position // to space as if we were able to resize from space, even though from // space is not modified. // Giving eden priority was tried and gave poorer performance. to_end = (char*)pointer_delta(virtual_space()->high(), (char*)requested_survivor_size, sizeof(char)); to_end = MIN2(to_end, from_start); to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size, sizeof(char)); // if the space sizes are to be increased by several times then // 'to_start' will point beyond the young generation. In this case // 'to_start' should be adjusted. to_start = MAX2(to_start, eden_start + alignment); // Compute how big eden can be, then adjust end. // See comments above on calculating eden_end. size_t eden_size; if (maintain_minimum) { eden_size = pointer_delta(to_start, eden_start, sizeof(char)); } else { eden_size = MIN2(requested_eden_size, pointer_delta(to_start, eden_start, sizeof(char))); } eden_end = eden_start + eden_size; assert(eden_end >= eden_start, "addition overflowed"); // Could choose to not let eden shrink // to_start = MAX2(to_start, eden_end); // Don't let eden shrink down to 0 or less. eden_end = MAX2(eden_end, eden_start + alignment); to_start = MAX2(to_start, eden_end); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" [eden_start .. eden_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, eden_start, eden_end, pointer_delta(eden_end, eden_start, sizeof(char))); gclog_or_tty->print_cr(" [ to_start .. to_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, to_start, to_end, pointer_delta( to_end, to_start, sizeof(char))); gclog_or_tty->print_cr(" [from_start .. from_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, from_start, from_end, pointer_delta(from_end, from_start, sizeof(char))); } } guarantee((HeapWord*)from_start <= from_space()->bottom(), "from start moved to the right"); guarantee((HeapWord*)from_end >= from_space()->top(), "from end moved into live data"); assert(is_object_aligned((intptr_t)eden_start), "checking alignment"); assert(is_object_aligned((intptr_t)from_start), "checking alignment"); assert(is_object_aligned((intptr_t)to_start), "checking alignment"); MemRegion edenMR((HeapWord*)eden_start, (HeapWord*)eden_end); MemRegion toMR ((HeapWord*)to_start, (HeapWord*)to_end); MemRegion fromMR((HeapWord*)from_start, (HeapWord*)from_end); // Let's make sure the call to initialize doesn't reset "top"! HeapWord* old_from_top = from_space()->top(); // For PrintAdaptiveSizePolicy block below size_t old_from = from_space()->capacity_in_bytes(); size_t old_to = to_space()->capacity_in_bytes(); if (ZapUnusedHeapArea) { // NUMA is a special case because a numa space is not mangled // in order to not prematurely bind its address to memory to // the wrong memory (i.e., don't want the GC thread to first // touch the memory). The survivor spaces are not numa // spaces and are mangled. if (UseNUMA) { if (eden_from_to_order) { mangle_survivors(from_space(), fromMR, to_space(), toMR); } else { mangle_survivors(to_space(), toMR, from_space(), fromMR); } } // If not mangling the spaces, do some checking to verify that // the spaces are already mangled. // The spaces should be correctly mangled at this point so // do some checking here. Note that they are not being mangled // in the calls to initialize(). // Must check mangling before the spaces are reshaped. Otherwise, // the bottom or end of one space may have moved into an area // covered by another space and a failure of the check may // not correctly indicate which space is not properly mangled. HeapWord* limit = (HeapWord*) virtual_space()->high(); eden_space()->check_mangled_unused_area(limit); from_space()->check_mangled_unused_area(limit); to_space()->check_mangled_unused_area(limit); } // When an existing space is being initialized, it is not // mangled because the space has been previously mangled. eden_space()->initialize(edenMR, SpaceDecorator::Clear, SpaceDecorator::DontMangle); to_space()->initialize(toMR, SpaceDecorator::Clear, SpaceDecorator::DontMangle); from_space()->initialize(fromMR, SpaceDecorator::DontClear, SpaceDecorator::DontMangle); assert(from_space()->top() == old_from_top, "from top changed!"); if (PrintAdaptiveSizePolicy) { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " "collection: %d " "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " "(" SIZE_FORMAT ", " SIZE_FORMAT ") ", heap->total_collections(), old_from, old_to, from_space()->capacity_in_bytes(), to_space()->capacity_in_bytes()); gclog_or_tty->cr(); } }
signal_t *read_acq_signal() { guarantee(!empty()); return current_page_acq()->read_acq_signal(); }
void FreeRegionList::set_unrealistically_long_length(uint len) { guarantee(_unrealistically_long_length == 0, "should only be set once"); _unrealistically_long_length = len; }
explicit buf_parent_t(buf_lock_t *lock) : txn_(lock->txn()), lock_or_null_(lock) { guarantee(lock != nullptr); guarantee(!lock->empty()); }
void on_create(registration_id_t rid, peer_id_t peer, business_card_t business_card, auto_drainer_t::lock_t keepalive) { /* Grab the mutex to avoid race conditions if a message arrives at the update mailbox or the delete mailbox while we're working. We must not block between when `on_create()` begins and when `mutex_acq` is constructed. */ mutex_t::acq_t mutex_acq(&mutex); /* If the registrant has already deregistered but the deregistration message arrived ahead of the registration message, it will have left a NULL in the `registrations` map. */ typename std::map<registration_id_t, cond_t *>::iterator it = registrations.find(rid); if (it != registrations.end()) { guarantee(it->second == NULL); registrations.erase(it); return; } /* Construct a `registrant_t` to tell the controller that something has now registered. */ registrant_type registrant(controller, business_card); /* `registration` is the interface that we expose to the `on_update()` and `on_delete()` handlers. */ cond_t deletion_cond; /* Expose `deletion_cond` so that `on_delete()` can find it. */ map_insertion_sentry_t<registration_id_t, cond_t *> registration_map_sentry( ®istrations, rid, &deletion_cond); /* Begin monitoring the peer so we can disconnect when necessary. */ disconnect_watcher_t peer_monitor(mailbox_manager->get_connectivity_service(), peer); /* Release the mutex, since we're done with our initial setup phase */ { mutex_t::acq_t doomed; swap(mutex_acq, doomed); } /* Wait till it's time to shut down */ wait_any_t waiter(&deletion_cond, &peer_monitor, keepalive.get_drain_signal()); waiter.wait_lazily_unordered(); /* Reacquire the mutex, to avoid race conditions when we're deregistering from `deleters`. I'm not sure if there re any such race conditions, but better safe than sorry. */ { mutex_t::acq_t reacquisition(&mutex); swap(mutex_acq, reacquisition); } /* `registration_map_sentry` destructor run here; `deletion_cond` cannot be pulsed after this. */ /* `deletion_cond` destructor run here. */ /* `registrant` destructor run here; this will tell the controller that the registration is dead and gone. */ /* `mutex_acq` destructor run here; it's safe to release the mutex because we're no longer touching `updaters` or `deleters`. */ }
cache_t *cache() const { guarantee(!empty()); return txn_->cache(); }
JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, JavaValue* result, TRAPS) { JavaThread* thread = (JavaThread *)THREAD; bool clear_pending_exception = true; guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); assert(!thread->owns_locks(), "must release all locks when leaving VM"); guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler"); _result = result; // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub, // since it can potentially block. JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread); // After this, we are official in JavaCode. This needs to be done before we change any of the thread local // info, since we cannot find oops before the new information is set up completely. ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_Java); // Make sure that we handle asynchronous stops and suspends _before_ we clear all thread state // in JavaCallWrapper::JavaCallWrapper(). This way, we can decide if we need to do any pd actions // to prepare for stop/suspend (flush register windows on sparcs, cache sp, or other state). if (thread->has_special_runtime_exit_condition()) { thread->handle_special_runtime_exit_condition(); if (HAS_PENDING_EXCEPTION) { clear_pending_exception = false; } } // Make sure to set the oop's after the thread transition - since we can block there. No one is GC'ing // the JavaCallWrapper before the entry frame is on the stack. _callee_method = callee_method(); _receiver = receiver(); #ifdef CHECK_UNHANDLED_OOPS THREAD->allow_unhandled_oop(&_receiver); #endif // CHECK_UNHANDLED_OOPS _thread = (JavaThread *)thread; _handles = _thread->active_handles(); // save previous handle block & Java frame linkage // For the profiler, the last_Java_frame information in thread must always be in // legal state. We have no last Java frame if last_Java_sp == NULL so // the valid transition is to clear _last_Java_sp and then reset the rest of // the (platform specific) state. _anchor.copy(_thread->frame_anchor()); _thread->frame_anchor()->clear(); debug_only(_thread->inc_java_call_counter()); _thread->set_active_handles(new_handles); // install new handle block and reset Java frame linkage assert (_thread->thread_state() != _thread_in_native, "cannot set native pc to NULL"); // clear any pending exception in thread (native calls start with no exception pending) if(clear_pending_exception) { _thread->clear_pending_exception(); } if (_anchor.last_Java_sp() == NULL) { _thread->record_base_of_stack_pointer(); } }
// Write the field information portion of ClassFile structure // JVMSpec| u2 fields_count; // JVMSpec| field_info fields[fields_count]; void JvmtiClassFileReconstituter::write_field_infos() { HandleMark hm(thread()); objArrayHandle fields_anno(thread(), ikh()->fields_annotations()); // Compute the real number of Java fields int java_fields = ikh()->java_fields_count(); write_u2(java_fields); for (JavaFieldStream fs(ikh()); !fs.done(); fs.next()) { AccessFlags access_flags = fs.access_flags(); int name_index = fs.name_index(); int signature_index = fs.signature_index(); int initial_value_index = fs.initval_index(); guarantee(name_index != 0 && signature_index != 0, "bad constant pool index for field"); // int offset = ikh()->field_offset( index ); int generic_signature_index = fs.generic_signature_index(); typeArrayHandle anno(thread(), fields_anno.not_null() ? (typeArrayOop)(fields_anno->obj_at(fs.index())) : (typeArrayOop)NULL); // JVMSpec| field_info { // JVMSpec| u2 access_flags; // JVMSpec| u2 name_index; // JVMSpec| u2 descriptor_index; // JVMSpec| u2 attributes_count; // JVMSpec| attribute_info attributes[attributes_count]; // JVMSpec| } write_u2(access_flags.as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS); write_u2(name_index); write_u2(signature_index); int attr_count = 0; if (initial_value_index != 0) { ++attr_count; } if (access_flags.is_synthetic()) { // ++attr_count; } if (generic_signature_index != 0) { ++attr_count; } if (anno.not_null()) { ++attr_count; // has RuntimeVisibleAnnotations attribute } write_u2(attr_count); if (initial_value_index != 0) { write_attribute_name_index("ConstantValue"); write_u4(2); //length always 2 write_u2(initial_value_index); } if (access_flags.is_synthetic()) { // write_synthetic_attribute(); } if (generic_signature_index != 0) { write_signature_attribute(generic_signature_index); } if (anno.not_null()) { write_annotations_attribute("RuntimeVisibleAnnotations", anno); } } }
// Similar to PSYoungGen::resize_generation() but // allows sum of eden_size and 2 * survivor_size to exceed _max_gen_size // expands at the low end of the virtual space // moves the boundary between the generations in order to expand // some additional diagnostics // If no additional changes are required, this can be deleted // and the changes factored back into PSYoungGen::resize_generation(). bool ASPSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) { const size_t alignment = virtual_space()->alignment(); size_t orig_size = virtual_space()->committed_size(); bool size_changed = false; // There used to be a guarantee here that // (eden_size + 2*survivor_size) <= _max_gen_size // This requirement is enforced by the calculation of desired_size // below. It may not be true on entry since the size of the // eden_size is no bounded by the generation size. assert(max_size() == reserved().byte_size(), "max gen size problem?"); assert(min_gen_size() <= orig_size && orig_size <= max_size(), "just checking"); // Adjust new generation size const size_t eden_plus_survivors = align_size_up(eden_size + 2 * survivor_size, alignment); size_t desired_size = MAX2(MIN2(eden_plus_survivors, gen_size_limit()), min_gen_size()); assert(desired_size <= gen_size_limit(), "just checking"); if (desired_size > orig_size) { // Grow the generation size_t change = desired_size - orig_size; HeapWord* prev_low = (HeapWord*) virtual_space()->low(); if (!virtual_space()->expand_by(change)) { return false; } if (ZapUnusedHeapArea) { // Mangle newly committed space immediately because it // can be done here more simply that after the new // spaces have been computed. HeapWord* new_low = (HeapWord*) virtual_space()->low(); assert(new_low < prev_low, "Did not grow"); MemRegion mangle_region(new_low, prev_low); SpaceMangler::mangle_region(mangle_region); } size_changed = true; } else if (desired_size < orig_size) { size_t desired_change = orig_size - desired_size; // How much is available for shrinking. size_t available_bytes = limit_gen_shrink(desired_change); size_t change = MIN2(desired_change, available_bytes); virtual_space()->shrink_by(change); size_changed = true; } else { if (Verbose && PrintGC) { if (orig_size == gen_size_limit()) { gclog_or_tty->print_cr("ASPSYoung generation size at maximum: " SIZE_FORMAT "K", orig_size/K); } else if (orig_size == min_gen_size()) { gclog_or_tty->print_cr("ASPSYoung generation size at minium: " SIZE_FORMAT "K", orig_size/K); } } } if (size_changed) { reset_after_change(); if (Verbose && PrintGC) { size_t current_size = virtual_space()->committed_size(); gclog_or_tty->print_cr("ASPSYoung generation size changed: " SIZE_FORMAT "K->" SIZE_FORMAT "K", orig_size/K, current_size/K); } } guarantee(eden_plus_survivors <= virtual_space()->committed_size() || virtual_space()->committed_size() == max_size(), "Sanity"); return true; }
~PlatformParker() { guarantee(0, "invariant"); }
void VM_Version::initialize() { _features = determine_features(); PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes(); PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); PrefetchFieldsAhead = prefetch_fields_ahead(); assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 1, "invalid value"); if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; if( AllocatePrefetchInstr > 1 ) AllocatePrefetchInstr = 0; // Allocation prefetch settings intx cache_line_size = prefetch_data_size(); if( cache_line_size > AllocatePrefetchStepSize ) AllocatePrefetchStepSize = cache_line_size; assert(AllocatePrefetchLines > 0, "invalid value"); if( AllocatePrefetchLines < 1 ) // set valid value in product VM AllocatePrefetchLines = 3; assert(AllocateInstancePrefetchLines > 0, "invalid value"); if( AllocateInstancePrefetchLines < 1 ) // set valid value in product VM AllocateInstancePrefetchLines = 1; AllocatePrefetchDistance = allocate_prefetch_distance(); AllocatePrefetchStyle = allocate_prefetch_style(); assert((AllocatePrefetchDistance % AllocatePrefetchStepSize) == 0 && (AllocatePrefetchDistance > 0), "invalid value"); if ((AllocatePrefetchDistance % AllocatePrefetchStepSize) != 0 || (AllocatePrefetchDistance <= 0)) { AllocatePrefetchDistance = AllocatePrefetchStepSize; } if (AllocatePrefetchStyle == 3 && !has_blk_init()) { warning("BIS instructions are not available on this CPU"); FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); } guarantee(VM_Version::has_v9(), "only SPARC v9 is supported"); assert(ArraycopySrcPrefetchDistance < 4096, "invalid value"); if (ArraycopySrcPrefetchDistance >= 4096) ArraycopySrcPrefetchDistance = 4064; assert(ArraycopyDstPrefetchDistance < 4096, "invalid value"); if (ArraycopyDstPrefetchDistance >= 4096) ArraycopyDstPrefetchDistance = 4064; UseSSE = 0; // Only on x86 and x64 _supports_cx8 = has_v9(); _supports_atomic_getset4 = true; // swap instruction // There are Fujitsu Sparc64 CPUs which support blk_init as well so // we have to take this check out of the 'is_niagara()' block below. if (has_blk_init()) { // When using CMS or G1, we cannot use memset() in BOT updates // because the sun4v/CMT version in libc_psr uses BIS which // exposes "phantom zeros" to concurrent readers. See 6948537. if (FLAG_IS_DEFAULT(UseMemSetInBOT) && (UseConcMarkSweepGC || UseG1GC)) { FLAG_SET_DEFAULT(UseMemSetInBOT, false); } // Issue a stern warning if the user has explicitly set // UseMemSetInBOT (it is known to cause issues), but allow // use for experimentation and debugging. if (UseConcMarkSweepGC || UseG1GC) { if (UseMemSetInBOT) { assert(!FLAG_IS_DEFAULT(UseMemSetInBOT), "Error"); warning("Experimental flag -XX:+UseMemSetInBOT is known to cause instability" " on sun4v; please understand that you are using at your own risk!"); } } } if (is_niagara()) { // Indirect branch is the same cost as direct if (FLAG_IS_DEFAULT(UseInlineCaches)) { FLAG_SET_DEFAULT(UseInlineCaches, false); } // Align loops on a single instruction boundary. if (FLAG_IS_DEFAULT(OptoLoopAlignment)) { FLAG_SET_DEFAULT(OptoLoopAlignment, 4); } #ifdef _LP64 // 32-bit oops don't make sense for the 64-bit VM on sparc // since the 32-bit VM has the same registers and smaller objects. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); #endif // _LP64 #ifdef COMPILER2 // Indirect branch is the same cost as direct if (FLAG_IS_DEFAULT(UseJumpTables)) { FLAG_SET_DEFAULT(UseJumpTables, true); } // Single-issue, so entry and loop tops are // aligned on a single instruction boundary if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) { FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); } if (is_niagara_plus()) { if (has_blk_init() && UseTLAB && FLAG_IS_DEFAULT(AllocatePrefetchInstr)) { // Use BIS instruction for TLAB allocation prefetch. FLAG_SET_ERGO(intx, AllocatePrefetchInstr, 1); if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { FLAG_SET_ERGO(intx, AllocatePrefetchStyle, 3); } if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { // Use smaller prefetch distance with BIS FLAG_SET_DEFAULT(AllocatePrefetchDistance, 64); } } if (is_T4()) { // Double number of prefetched cache lines on T4 // since L2 cache line size is smaller (32 bytes). if (FLAG_IS_DEFAULT(AllocatePrefetchLines)) { FLAG_SET_ERGO(intx, AllocatePrefetchLines, AllocatePrefetchLines*2); } if (FLAG_IS_DEFAULT(AllocateInstancePrefetchLines)) { FLAG_SET_ERGO(intx, AllocateInstancePrefetchLines, AllocateInstancePrefetchLines*2); } } if (AllocatePrefetchStyle != 3 && FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { // Use different prefetch distance without BIS FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256); } if (AllocatePrefetchInstr == 1) { // Need a space at the end of TLAB for BIS since it // will fault when accessing memory outside of heap. // +1 for rounding up to next cache line, +1 to be safe int lines = AllocatePrefetchLines + 2; int step_size = AllocatePrefetchStepSize; int distance = AllocatePrefetchDistance; _reserve_for_allocation_prefetch = (distance + step_size*lines)/(int)HeapWordSize; } } #endif } // Use hardware population count instruction if available. if (has_hardware_popc()) { if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { FLAG_SET_DEFAULT(UsePopCountInstruction, true); } } else if (UsePopCountInstruction) { warning("POPC instruction is not available on this CPU"); FLAG_SET_DEFAULT(UsePopCountInstruction, false); } // T4 and newer Sparc cpus have new compare and branch instruction. if (has_cbcond()) { if (FLAG_IS_DEFAULT(UseCBCond)) { FLAG_SET_DEFAULT(UseCBCond, true); } } else if (UseCBCond) { warning("CBCOND instruction is not available on this CPU"); FLAG_SET_DEFAULT(UseCBCond, false); } assert(BlockZeroingLowLimit > 0, "invalid value"); if (has_block_zeroing() && cache_line_size > 0) { if (FLAG_IS_DEFAULT(UseBlockZeroing)) { FLAG_SET_DEFAULT(UseBlockZeroing, true); } } else if (UseBlockZeroing) { warning("BIS zeroing instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseBlockZeroing, false); } assert(BlockCopyLowLimit > 0, "invalid value"); if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache if (FLAG_IS_DEFAULT(UseBlockCopy)) { FLAG_SET_DEFAULT(UseBlockCopy, true); } } else if (UseBlockCopy) { warning("BIS instructions are not available or expensive on this CPU"); FLAG_SET_DEFAULT(UseBlockCopy, false); } #ifdef COMPILER2 // T4 and newer Sparc cpus have fast RDPC. if (has_fast_rdpc() && FLAG_IS_DEFAULT(UseRDPCForConstantTableBase)) { FLAG_SET_DEFAULT(UseRDPCForConstantTableBase, true); } // Currently not supported anywhere. FLAG_SET_DEFAULT(UseFPUForSpilling, false); MaxVectorSize = 8; assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); #endif assert((CodeEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); char buf[512]; jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_v9() ? ", v9" : (has_v8() ? ", v8" : "")), (has_hardware_popc() ? ", popc" : ""), (has_vis1() ? ", vis1" : ""), (has_vis2() ? ", vis2" : ""), (has_vis3() ? ", vis3" : ""), (has_blk_init() ? ", blk_init" : ""), (has_cbcond() ? ", cbcond" : ""), (has_aes() ? ", aes" : ""), (has_sha1() ? ", sha1" : ""), (has_sha256() ? ", sha256" : ""), (has_sha512() ? ", sha512" : ""), (has_crc32c() ? ", crc32c" : ""), (is_ultra3() ? ", ultra3" : ""), (is_sun4v() ? ", sun4v" : ""), (is_niagara_plus() ? ", niagara_plus" : (is_niagara() ? ", niagara" : "")), (is_sparc64() ? ", sparc64" : ""), (!has_hardware_mul32() ? ", no-mul32" : ""), (!has_hardware_div32() ? ", no-div32" : ""), (!has_hardware_fsmuld() ? ", no-fsmuld" : "")); // buf is started with ", " or is empty _features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf); // UseVIS is set to the smallest of what hardware supports and what // the command line requires. I.e., you cannot set UseVIS to 3 on // older UltraSparc which do not support it. if (UseVIS > 3) UseVIS=3; if (UseVIS < 0) UseVIS=0; if (!has_vis3()) // Drop to 2 if no VIS3 support UseVIS = MIN2((intx)2,UseVIS); if (!has_vis2()) // Drop to 1 if no VIS2 support UseVIS = MIN2((intx)1,UseVIS); if (!has_vis1()) // Drop to 0 if no VIS1 support UseVIS = 0; // SPARC T4 and above should have support for AES instructions if (has_aes()) { if (UseVIS > 2) { // AES intrinsics use MOVxTOd/MOVdTOx which are VIS3 if (FLAG_IS_DEFAULT(UseAES)) { FLAG_SET_DEFAULT(UseAES, true); } if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { FLAG_SET_DEFAULT(UseAESIntrinsics, true); } // we disable both the AES flags if either of them is disabled on the command line if (!UseAES || !UseAESIntrinsics) { FLAG_SET_DEFAULT(UseAES, false); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } } else { if (UseAES || UseAESIntrinsics) { warning("SPARC AES intrinsics require VIS3 instruction support. Intrinsics will be disabled."); if (UseAES) { FLAG_SET_DEFAULT(UseAES, false); } if (UseAESIntrinsics) { FLAG_SET_DEFAULT(UseAESIntrinsics, false); } } } } else if (UseAES || UseAESIntrinsics) { warning("AES instructions are not available on this CPU"); if (UseAES) { FLAG_SET_DEFAULT(UseAES, false); } if (UseAESIntrinsics) { FLAG_SET_DEFAULT(UseAESIntrinsics, false); } } // GHASH/GCM intrinsics if (has_vis3() && (UseVIS > 2)) { if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { UseGHASHIntrinsics = true; } } else if (UseGHASHIntrinsics) { if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) warning("GHASH intrinsics require VIS3 instruction support. Intrinsics will be disabled"); FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); } // SHA1, SHA256, and SHA512 instructions were added to SPARC T-series at different times if (has_sha1() || has_sha256() || has_sha512()) { if (UseVIS > 0) { // SHA intrinsics use VIS1 instructions if (FLAG_IS_DEFAULT(UseSHA)) { FLAG_SET_DEFAULT(UseSHA, true); } } else { if (UseSHA) { warning("SPARC SHA intrinsics require VIS1 instruction support. Intrinsics will be disabled."); FLAG_SET_DEFAULT(UseSHA, false); } } } else if (UseSHA) { warning("SHA instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseSHA, false); } if (UseSHA && has_sha1()) { if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) { FLAG_SET_DEFAULT(UseSHA1Intrinsics, true); } } else if (UseSHA1Intrinsics) { warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); } if (UseSHA && has_sha256()) { if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); } } else if (UseSHA256Intrinsics) { warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); } if (UseSHA && has_sha512()) { if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } } else if (UseSHA512Intrinsics) { warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA, false); } // SPARC T4 and above should have support for CRC32C instruction if (has_crc32c()) { if (UseVIS > 2) { // CRC32C intrinsics use VIS3 instructions if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true); } } else { if (UseCRC32CIntrinsics) { warning("SPARC CRC32C intrinsics require VIS3 instruction support. Intrinsics will be disabled."); FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); } } } else if (UseCRC32CIntrinsics) { warning("CRC32C instruction is not available on this CPU"); FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); } if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; // This machine does not allow unaligned memory accesses if (UseUnalignedAccesses) { if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) warning("Unaligned memory access is not available on this CPU"); FLAG_SET_DEFAULT(UseUnalignedAccesses, false); } #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { tty->print_cr(": no prefetching"); } else { tty->print(" prefetching: "); if (AllocatePrefetchInstr == 0) { tty->print("PREFETCH"); } else if (AllocatePrefetchInstr == 1) { tty->print("BIS"); } if (AllocatePrefetchLines > 1) { tty->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize); } else { tty->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize); } } if (PrefetchCopyIntervalInBytes > 0) { tty->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); } if (PrefetchScanIntervalInBytes > 0) { tty->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); } if (PrefetchFieldsAhead > 0) { tty->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); } if (ContendedPaddingWidth > 0) { tty->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); } } #endif // PRODUCT }