src/share/vm/opto/callnode.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hotspot Cdiff src/share/vm/opto/callnode.cpp
src/share/vm/opto/callnode.cpp
Print this page
rev 7690 : 6912521: System.arraycopy works slower than the simple loop for little lengths
Summary: convert small array copies to series of loads and stores
Reviewed-by:
rev 7691 : 6912521: System.arraycopy works slower than the simple loop for little lengths
Summary: convert small array copies to series of loads and stores
Reviewed-by:
*** 1816,2009 ****
}
}
return result;
}
- ArrayCopyNode::ArrayCopyNode(Compile* C, bool alloc_tightly_coupled)
- : CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM),
- _alloc_tightly_coupled(alloc_tightly_coupled),
- _kind(None),
- _arguments_validated(false) {
- init_class_id(Class_ArrayCopy);
- init_flags(Flag_is_macro);
- C->add_macro_node(this);
- }
-
- uint ArrayCopyNode::size_of() const { return sizeof(*this); }
-
- ArrayCopyNode* ArrayCopyNode::make(GraphKit* kit, bool may_throw,
- Node* src, Node* src_offset,
- Node* dest, Node* dest_offset,
- Node* length,
- bool alloc_tightly_coupled,
- Node* src_klass, Node* dest_klass,
- Node* src_length, Node* dest_length) {
-
- ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled);
- Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac);
-
- ac->init_req(ArrayCopyNode::Src, src);
- ac->init_req(ArrayCopyNode::SrcPos, src_offset);
- ac->init_req(ArrayCopyNode::Dest, dest);
- ac->init_req(ArrayCopyNode::DestPos, dest_offset);
- ac->init_req(ArrayCopyNode::Length, length);
- ac->init_req(ArrayCopyNode::SrcLen, src_length);
- ac->init_req(ArrayCopyNode::DestLen, dest_length);
- ac->init_req(ArrayCopyNode::SrcKlass, src_klass);
- ac->init_req(ArrayCopyNode::DestKlass, dest_klass);
-
- if (may_throw) {
- ac->set_req(TypeFunc::I_O , kit->i_o());
- kit->add_safepoint_edges(ac, false);
- }
-
- return ac;
- }
-
- void ArrayCopyNode::connect_outputs(GraphKit* kit) {
- kit->set_all_memory_call(this, true);
- kit->set_control(kit->gvn().transform(new ProjNode(this,TypeFunc::Control)));
- kit->set_i_o(kit->gvn().transform(new ProjNode(this, TypeFunc::I_O)));
- kit->make_slow_call_ex(this, kit->env()->Throwable_klass(), true);
- kit->set_all_memory_call(this);
- }
-
- #ifndef PRODUCT
- const char* ArrayCopyNode::_kind_names[] = {"arraycopy", "arraycopy, validated arguments", "clone", "oop array clone", "CopyOf", "CopyOfRange"};
- void ArrayCopyNode::dump_spec(outputStream *st) const {
- CallNode::dump_spec(st);
- st->print(" (%s%s)", _kind_names[_kind], _alloc_tightly_coupled ? ", tightly coupled allocation" : "");
- }
- #endif
-
- int ArrayCopyNode::get_count(PhaseGVN *phase) const {
- Node* src = in(ArrayCopyNode::Src);
- const Type* src_type = phase->type(src);
-
- assert(is_clonebasic(), "unexpected arraycopy type");
- if (src_type->isa_instptr()) {
- const TypeInstPtr* inst_src = src_type->is_instptr();
- ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
- // ciInstanceKlass::nof_nonstatic_fields() doesn't take injected
- // fields into account. They are rare anyway so easier to simply
- // skip instances with injected fields.
- if ((!inst_src->klass_is_exact() && (ik->is_interface() || ik->has_subklass())) || ik->has_injected_fields()) {
- return -1;
- }
- int nb_fields = ik->nof_nonstatic_fields();
- return nb_fields;
- }
- return -1;
- }
-
- Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int count) {
- assert(is_clonebasic(), "unexpected arraycopy type");
-
- Node* src = in(ArrayCopyNode::Src);
- Node* dest = in(ArrayCopyNode::Dest);
- Node* ctl = in(TypeFunc::Control);
- Node* in_mem = in(TypeFunc::Memory);
-
- const Type* src_type = phase->type(src);
- const Type* dest_type = phase->type(dest);
-
- assert(src->is_AddP(), "should be base + off");
- assert(dest->is_AddP(), "should be base + off");
- Node* base_src = src->in(AddPNode::Base);
- Node* base_dest = dest->in(AddPNode::Base);
-
- MergeMemNode* mem = MergeMemNode::make(in_mem);
-
- const TypeInstPtr* inst_src = src_type->is_instptr();
-
- if (!inst_src->klass_is_exact()) {
- ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
- assert(!ik->is_interface() && !ik->has_subklass(), "inconsistent klass hierarchy");
- phase->C->dependencies()->assert_leaf_type(ik);
- }
-
- ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
- assert(ik->nof_nonstatic_fields() <= ArrayCopyLoadStoreMaxElem, "too many fields");
-
- for (int i = 0; i < count; i++) {
- ciField* field = ik->nonstatic_field_at(i);
- int fieldidx = phase->C->alias_type(field)->index();
- const TypePtr* adr_type = phase->C->alias_type(field)->adr_type();
- Node* off = phase->MakeConX(field->offset());
- Node* next_src = phase->transform(new AddPNode(base_src,base_src,off));
- Node* next_dest = phase->transform(new AddPNode(base_dest,base_dest,off));
- BasicType bt = field->layout_type();
-
- const Type *type;
- if (bt == T_OBJECT) {
- if (!field->type()->is_loaded()) {
- type = TypeInstPtr::BOTTOM;
- } else {
- ciType* field_klass = field->type();
- type = TypeOopPtr::make_from_klass(field_klass->as_klass());
- }
- } else {
- type = Type::get_const_basic_type(bt);
- }
-
- Node* v = LoadNode::make(*phase, ctl, mem->memory_at(fieldidx), next_src, adr_type, type, bt, MemNode::unordered);
- v = phase->transform(v);
- Node* s = StoreNode::make(*phase, ctl, mem->memory_at(fieldidx), next_dest, adr_type, v, bt, MemNode::unordered);
- s = phase->transform(s);
- mem->set_memory_at(fieldidx, s);
- }
-
- if (!finish_transform(phase, can_reshape, ctl, mem)) {
- return NULL;
- }
-
- return mem;
- }
-
- bool ArrayCopyNode::finish_transform(PhaseGVN *phase, bool can_reshape,
- Node* ctl, Node *mem) {
- if (can_reshape) {
- PhaseIterGVN* igvn = phase->is_IterGVN();
- assert(is_clonebasic(), "unexpected arraycopy type");
- Node* out_mem = proj_out(TypeFunc::Memory);
-
- if (out_mem->outcnt() != 1 || !out_mem->raw_out(0)->is_MergeMem() ||
- out_mem->raw_out(0)->outcnt() != 1 || !out_mem->raw_out(0)->raw_out(0)->is_MemBar()) {
- assert(!GraphKit::use_ReduceInitialCardMarks(), "can only happen with card marking");
- return false;
- }
-
- igvn->replace_node(out_mem->raw_out(0), mem);
-
- Node* out_ctl = proj_out(TypeFunc::Control);
- igvn->replace_node(out_ctl, ctl);
- }
- return true;
- }
-
-
- Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
-
- if (StressArrayCopyMacroNode && !can_reshape) return NULL;
-
- // See if it's a small array copy and we can inline it as
- // loads/stores
- // Here we can only do:
- // - clone for which we don't need to do card marking
-
- if (!is_clonebasic()) {
- return NULL;
- }
-
- if (in(TypeFunc::Control)->is_top() || in(TypeFunc::Memory)->is_top()) {
- return NULL;
- }
-
- int count = get_count(phase);
-
- if (count < 0 || count > ArrayCopyLoadStoreMaxElem) {
- return NULL;
- }
-
- Node* mem = try_clone_instance(phase, can_reshape, count);
- return mem;
- }
--- 1816,1820 ----
src/share/vm/opto/callnode.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File