Функция SetByteArrayRegion
реализована как
JNI_ENTRY(void, \
jni_Set##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, \
jsize len, const ElementType *buf)) \
JNIWrapper("Set" XSTR(Result) "ArrayRegion"); \
DTRACE_PROBE5(hotspot_jni, Set##Result##ArrayRegion__entry, env, array, start, len, buf);\
DT_VOID_RETURN_MARK(Set##Result##ArrayRegion); \
typeArrayOop dst = typeArrayOop(JNIHandles::resolve_non_null(array)); \
if (start < 0 || len < 0 || ((unsigned int)start + (unsigned int)len > (unsigned int)dst->length())) { \
THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
} else { \
if (len > 0) { \
int sc = TypeArrayKlass::cast(dst->klass())->log2_element_size(); \
memcpy((u_char*) dst->Tag##_at_addr(start), \
(u_char*) buf, \
len << sc); \
} \
} \
JNI_END
Как можно заметить, он вызывает memcpy
для собственного указателя на массив кучи Java: dst->Tag##_at_addr(start)
. memcpy
само по себе не является атомарным, поэтому я пришел к выводу, что ничто не мешает GC перемещать массив в середине вызова memcpy
.
Кроме того, массив можно переместить куда-то сразу после dst->Tag##_at_addr(start)
, что снова приведет к повреждению памяти.
По контракту "критические" методы используют GC_locker::lock_critical(thread);
.
Так почему же SetArrayRegion
методы безопасны? Что я пропустил?