[LEGACY MM] Escape making extra increments and decrements during coping to the same array (#4731)
(cherry picked from commit 8b601d8e2c6bc772386ebd88d303a032a6f54237)
This commit is contained in:
@@ -2192,6 +2192,37 @@ void updateHeapRef(ObjHeader** location, const ObjHeader* object) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool Strict>
|
||||||
|
void updateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) {
|
||||||
|
// In case of coping inside same array number of decrements and increments of RC can be decreased.
|
||||||
|
auto countIndex = [=](int i) { return (fromIndex < toIndex) ? count - 1 - i : i; };
|
||||||
|
int rewrittenElementsNumber = std::abs(fromIndex - toIndex);
|
||||||
|
// Release rewritten elements.
|
||||||
|
for (int i = 0; i < rewrittenElementsNumber; i++) {
|
||||||
|
int index = countIndex(i);
|
||||||
|
ObjHeader* old = *ArrayAddressOfElementAt(array, toIndex + index);
|
||||||
|
*const_cast<const ObjHeader**>(ArrayAddressOfElementAt(array, toIndex + index)) =
|
||||||
|
*ArrayAddressOfElementAt(array, fromIndex + index);
|
||||||
|
if (old != nullptr) {
|
||||||
|
releaseHeapRef<Strict>(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = rewrittenElementsNumber; i < count - rewrittenElementsNumber; i++) {
|
||||||
|
int index = countIndex(i);
|
||||||
|
*const_cast<const ObjHeader**>(ArrayAddressOfElementAt(array, toIndex + index)) =
|
||||||
|
*ArrayAddressOfElementAt(array, fromIndex + index);
|
||||||
|
}
|
||||||
|
for (int i = count - rewrittenElementsNumber; i < count; i++) {
|
||||||
|
int index = countIndex(i);
|
||||||
|
ObjHeader* object = *ArrayAddressOfElementAt(array, fromIndex + index);
|
||||||
|
// Add extra heap ref for copied elements.
|
||||||
|
if (object != nullptr) {
|
||||||
|
addHeapRef(object);
|
||||||
|
}
|
||||||
|
*const_cast<const ObjHeader**>(ArrayAddressOfElementAt(array, toIndex + index)) = object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <bool Strict>
|
template <bool Strict>
|
||||||
void updateStackRef(ObjHeader** location, const ObjHeader* object) {
|
void updateStackRef(ObjHeader** location, const ObjHeader* object) {
|
||||||
UPDATE_REF_EVENT(memoryState, *location, object, location, 1)
|
UPDATE_REF_EVENT(memoryState, *location, object, location, 1)
|
||||||
@@ -3367,6 +3398,15 @@ RUNTIME_NOTHROW void UpdateHeapRefRelaxed(ObjHeader** location, const ObjHeader*
|
|||||||
updateHeapRef<false>(location, object);
|
updateHeapRef<false>(location, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArrayStrict(const ArrayHeader* array, int fromIndex, int toIndex,
|
||||||
|
int count) {
|
||||||
|
updateHeapRefsInsideOneArray<true>(array, fromIndex, toIndex, count);
|
||||||
|
}
|
||||||
|
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArrayRelaxed(const ArrayHeader* array, int fromIndex, int toIndex,
|
||||||
|
int count) {
|
||||||
|
updateHeapRefsInsideOneArray<false>(array, fromIndex, toIndex, count);
|
||||||
|
}
|
||||||
|
|
||||||
RUNTIME_NOTHROW void UpdateReturnRefStrict(ObjHeader** returnSlot, const ObjHeader* value) {
|
RUNTIME_NOTHROW void UpdateReturnRefStrict(ObjHeader** returnSlot, const ObjHeader* value) {
|
||||||
updateReturnRef<true>(returnSlot, value);
|
updateReturnRef<true>(returnSlot, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,6 +322,8 @@ MODEL_VARIANTS(void, UpdateStackRef, ObjHeader** location, const ObjHeader* obje
|
|||||||
MODEL_VARIANTS(void, UpdateHeapRef, ObjHeader** location, const ObjHeader* object);
|
MODEL_VARIANTS(void, UpdateHeapRef, ObjHeader** location, const ObjHeader* object);
|
||||||
MODEL_VARIANTS(void, UpdateHeapRefIfNull, ObjHeader** location, const ObjHeader* object);
|
MODEL_VARIANTS(void, UpdateHeapRefIfNull, ObjHeader** location, const ObjHeader* object);
|
||||||
MODEL_VARIANTS(void, UpdateReturnRef, ObjHeader** returnSlot, const ObjHeader* object);
|
MODEL_VARIANTS(void, UpdateReturnRef, ObjHeader** returnSlot, const ObjHeader* object);
|
||||||
|
MODEL_VARIANTS(void, UpdateHeapRefsInsideOneArray, const ArrayHeader* array, int fromIndex, int toIndex,
|
||||||
|
int count);
|
||||||
MODEL_VARIANTS(void, EnterFrame, ObjHeader** start, int parameters, int count);
|
MODEL_VARIANTS(void, EnterFrame, ObjHeader** start, int parameters, int count);
|
||||||
MODEL_VARIANTS(void, LeaveFrame, ObjHeader** start, int parameters, int count);
|
MODEL_VARIANTS(void, LeaveFrame, ObjHeader** start, int parameters, int count);
|
||||||
|
|
||||||
|
|||||||
@@ -133,15 +133,20 @@ void Kotlin_Array_copyImpl(KConstRef thiz, KInt fromIndex,
|
|||||||
ThrowArrayIndexOutOfBoundsException();
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
mutabilityCheck(destination);
|
mutabilityCheck(destination);
|
||||||
if (fromIndex >= toIndex) {
|
if (CurrentMemoryModel != MemoryModel::kExperimental && array == destinationArray &&
|
||||||
for (int index = 0; index < count; index++) {
|
std::abs(fromIndex - toIndex) < count) {
|
||||||
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
UpdateHeapRefsInsideOneArray(array, fromIndex, toIndex, count);
|
||||||
*ArrayAddressOfElementAt(array, fromIndex + index));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (int index = count - 1; index >= 0; index--) {
|
if (fromIndex >= toIndex) {
|
||||||
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
for (int index = 0; index < count; index++) {
|
||||||
*ArrayAddressOfElementAt(array, fromIndex + index));
|
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
||||||
|
*ArrayAddressOfElementAt(array, fromIndex + index));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int index = count - 1; index >= 0; index--) {
|
||||||
|
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
||||||
|
*ArrayAddressOfElementAt(array, fromIndex + index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,6 +210,8 @@ void ZeroStackRef(ObjHeader** location) RUNTIME_NOTHROW;
|
|||||||
void UpdateStackRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
void UpdateStackRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
||||||
// Updates heap/static data location.
|
// Updates heap/static data location.
|
||||||
void UpdateHeapRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
void UpdateHeapRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
||||||
|
// Updates heap/static data in one array.
|
||||||
|
void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) RUNTIME_NOTHROW;
|
||||||
// Updates location if it is null, atomically.
|
// Updates location if it is null, atomically.
|
||||||
void UpdateHeapRefIfNull(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
void UpdateHeapRefIfNull(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
||||||
// Updates reference in return slot.
|
// Updates reference in return slot.
|
||||||
|
|||||||
@@ -189,6 +189,11 @@ extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateHeapRefIfNull(ObjHeader** lo
|
|||||||
mm::CompareAndSwapHeapRef(location, nullptr, const_cast<ObjHeader*>(object), &result);
|
mm::CompareAndSwapHeapRef(location, nullptr, const_cast<ObjHeader*>(object), &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex,
|
||||||
|
int toIndex, int count) {
|
||||||
|
RuntimeFail("Only for legacy MM");
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
|
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
|
||||||
mm::SetStackRef(returnSlot, const_cast<ObjHeader*>(object));
|
mm::SetStackRef(returnSlot, const_cast<ObjHeader*>(object));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,4 +67,8 @@ RUNTIME_NOTHROW void UpdateStackRef(ObjHeader** location, const ObjHeader* objec
|
|||||||
UpdateStackRefRelaxed(location, object);
|
UpdateStackRefRelaxed(location, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) {
|
||||||
|
UpdateHeapRefsInsideOneArrayRelaxed(array, fromIndex, toIndex, count);
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -67,4 +67,8 @@ RUNTIME_NOTHROW void UpdateStackRef(ObjHeader** location, const ObjHeader* objec
|
|||||||
UpdateStackRefStrict(location, object);
|
UpdateStackRefStrict(location, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) {
|
||||||
|
UpdateHeapRefsInsideOneArrayStrict(array, fromIndex, toIndex, count);
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
Reference in New Issue
Block a user