System.arraycopy 本地方法 源代码分析

来源:互联网 发布:淘宝积分换购物券 编辑:程序博客网 时间:2024/06/14 07:37

文章中源代码版本

JDK:jdk1.8.0_11

OpenJDK:openjdk-8u40-src-b25-10_feb_2015 【给出下载链接:openjdk8】


public static native void arraycopy(Object src,  int  srcPos,                                        Object dest, int destPos,                                        int length);


Java中的一个数组拷贝内容到另一个数组经常使用System.arraycopy()方法,但是查看源代码可以发现该方法声明为native,也就是说是本地方法,不是用Java写的。Java可以通过JNI来调用其他语言(主要还是C/C++语言)编写的方法。本文中就通过查看OpenJDK中的源码,简单分析一下System.arraycopy()方法的实现。如有不正确的地方,望指正!


1、打开openjdk\hotspot\src\share\vm\prims\jvm.cpp可以看到一个方法JVM_ArrayCopy,但是该方法没有真正实现复制的代码,而是简单的检测源数组和目的数组不为空,排除一些异常情况

/*java.lang.System中的arraycopy方法*/JVM_ENTRY(void, JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos,                               jobject dst, jint dst_pos, jint length))  JVMWrapper("JVM_ArrayCopy");  // Check if we have null pointers  //检查源数组和目的数组不为空  if (src == NULL || dst == NULL) {    THROW(vmSymbols::java_lang_NullPointerException());  }    arrayOop s = arrayOop(JNIHandles::resolve_non_null(src));  arrayOop d = arrayOop(JNIHandles::resolve_non_null(dst));  assert(s->is_oop(), "JVM_ArrayCopy: src not an oop");  assert(d->is_oop(), "JVM_ArrayCopy: dst not an oop");  // Do copy  //真正调用复制的方法  s->klass()->copy_array(s, src_pos, d, dst_pos, length, thread);JVM_END

2、openjdk\hotspot\src\share\vm\oops\objArrayKlass.cpp文件中copy_array方法

/*java.lang.System中的arraycopy方法具体实现*/void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,                               int dst_pos, int length, TRAPS) {  //检测s是数组  assert(s->is_objArray(), "must be obj array");  //目的数组不是数组对象的话,则抛出ArrayStoreException异常  if (!d->is_objArray()) {    THROW(vmSymbols::java_lang_ArrayStoreException());  }  // Check is all offsets and lengths are non negative  //检测下标参数非负  if (src_pos < 0 || dst_pos < 0 || length < 0) {    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());  }  // Check if the ranges are valid  //检测下标参数是否越界  if  ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length())     || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) {    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());  }  // Special case. Boundary cases must be checked first  // This allows the following call: copy_array(s, s.length(), d.length(), 0).  // This is correct, since the position is supposed to be an 'in between point', i.e., s.length(),  // points to the right of the last element.  //length==0则不需要复制  if (length==0) {    return;  }  //UseCompressedOops只是用来区分narrowOop和oop,具体2者有啥区别需要再研究  //调用do_copy函数来复制  if (UseCompressedOops) {    narrowOop* const src = objArrayOop(s)->obj_at_addr<narrowOop>(src_pos);    narrowOop* const dst = objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos);    do_copy<narrowOop>(s, src, d, dst, length, CHECK);  } else {    oop* const src = objArrayOop(s)->obj_at_addr<oop>(src_pos);    oop* const dst = objArrayOop(d)->obj_at_addr<oop>(dst_pos);    do_copy<oop> (s, src, d, dst, length, CHECK);  }}

do_copy方法

// Either oop or narrowOop depending on UseCompressedOops.template <class T> void ObjArrayKlass::do_copy(arrayOop s, T* src,                               arrayOop d, T* dst, int length, TRAPS) {  BarrierSet* bs = Universe::heap()->barrier_set();  // For performance reasons, we assume we are that the write barrier we  // are using has optimized modes for arrays of references.  At least one  // of the asserts below will fail if this is not the case.  assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");  assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well.");  if (s == d) {    // since source and destination are equal we do not need conversion checks.    assert(length > 0, "sanity check");    bs->write_ref_array_pre(dst, length);//复制的函数    Copy::conjoint_oops_atomic(src, dst, length);  } else {    // We have to make sure all elements conform to the destination array    Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();    Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();    if (stype == bound || stype->is_subtype_of(bound)) {      // elements are guaranteed to be subtypes, so no check necessary  //stype对象是bound,或者stype是bound的子类抑或stype实现bound接口      bs->write_ref_array_pre(dst, length);      Copy::conjoint_oops_atomic(src, dst, length);    } else {      // slow case: need individual subtype checks      // note: don't use obj_at_put below because it includes a redundant store check      T* from = src;      T* end = from + length;      for (T* p = dst; from < end; from++, p++) {        // XXX this is going to be slow.        T element = *from;        // even slower now        bool element_is_null = oopDesc::is_null(element);        oop new_val = element_is_null ? oop(NULL)                                      : oopDesc::decode_heap_oop_not_null(element);        if (element_is_null ||            (new_val->klass())->is_subtype_of(bound)) {          bs->write_ref_field_pre(p, new_val);          *p = element;        } else {          // We must do a barrier to cover the partial copy.          const size_t pd = pointer_delta(p, dst, (size_t)heapOopSize);          // pointer delta is scaled to number of elements (length field in          // objArrayOop) which we assume is 32 bit.          assert(pd == (size_t)(int)pd, "length field overflow");          bs->write_ref_array((HeapWord*)dst, pd);          THROW(vmSymbols::java_lang_ArrayStoreException());          return;        }      }    }  }  bs->write_ref_array((HeapWord*)dst, length);}

3、在openjdk\hotspot\src\share\vm\utilities\copy.hpp文件中找到该conjoint_oops_atomic函数,还有针对narrowOop的重载函数,这里不写出

 // oops,                  conjoint, atomic on each oop static void conjoint_oops_atomic(oop* from, oop* to, size_t count) {   assert_params_ok(from, to, LogBytesPerHeapOop);   pd_conjoint_oops_atomic(from, to, count); }

4、openjdk\hotspot\src\share\vm\oops\klass.hpp中的is_subtype_of函数

//检测是否是k的子类,或者是实现k接口  bool is_subtype_of(Klass* k) const {    juint    off = k->super_check_offset();    Klass* sup = *(Klass**)( (address)this + off );    const juint secondary_offset = in_bytes(secondary_super_cache_offset());    if (sup == k) {      return true;    } else if (off != secondary_offset) {      return false;    } else {      return search_secondary_supers(k);    }  }

5、openjdk\hotspot\src\os_cpu\windows_x86\vm\copy_windows_x86.inline.hpp,最主要就是pd_conjoint_oops_atomic函数

static void pd_conjoint_oops_atomic(oop* from, oop* to, size_t count) {  // Do better than this: inline memmove body  NEEDS CLEANUP  if (from > to) {    while (count-- > 0) {      // Copy forwards      *to++ = *from++;    }  } else {    from += count - 1;    to   += count - 1;    while (count-- > 0) {      // Copy backwards      *to-- = *from--;    }  }}




0 0