Remove remnants of concurrent memory model (#467)
This commit is contained in:
+4
-9
@@ -223,14 +223,14 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
}
|
}
|
||||||
fun storeAnyLocal(value: LLVMValueRef, ptr: LLVMValueRef) {
|
fun storeAnyLocal(value: LLVMValueRef, ptr: LLVMValueRef) {
|
||||||
if (isObjectRef(value)) {
|
if (isObjectRef(value)) {
|
||||||
updateLocalRef(value, ptr)
|
updateRef(value, ptr)
|
||||||
} else {
|
} else {
|
||||||
LLVMBuildStore(builder, value, ptr)
|
LLVMBuildStore(builder, value, ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun storeAnyGlobal(value: LLVMValueRef, ptr: LLVMValueRef) {
|
fun storeAnyGlobal(value: LLVMValueRef, ptr: LLVMValueRef) {
|
||||||
if (isObjectRef(value)) {
|
if (isObjectRef(value)) {
|
||||||
updateGlobalRef(value, ptr)
|
updateRef(value, ptr)
|
||||||
} else {
|
} else {
|
||||||
LLVMBuildStore(builder, value, ptr)
|
LLVMBuildStore(builder, value, ptr)
|
||||||
}
|
}
|
||||||
@@ -245,13 +245,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only use ignoreOld, when sure that memory is freshly inited and have no value.
|
// Only use ignoreOld, when sure that memory is freshly inited and have no value.
|
||||||
fun updateLocalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
fun updateRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
||||||
call(if (ignoreOld) context.llvm.setLocalRefFunction else context.llvm.updateLocalRefFunction,
|
call(if (ignoreOld) context.llvm.setRefFunction else context.llvm.updateRefFunction,
|
||||||
listOf(address, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateGlobalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
|
||||||
call(if (ignoreOld) context.llvm.setGlobalRefFunction else context.llvm.updateGlobalRefFunction,
|
|
||||||
listOf(address, value))
|
listOf(address, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-7
@@ -249,14 +249,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
||||||
val initInstanceFunction = importRtFunction("InitInstance")
|
val initInstanceFunction = importRtFunction("InitInstance")
|
||||||
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
|
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
|
||||||
val setLocalRefFunction = importRtFunction("SetLocalRef")
|
val setRefFunction = importRtFunction("SetRef")
|
||||||
val setGlobalRefFunction = importRtFunction("SetGlobalRef")
|
val updateRefFunction = importRtFunction("UpdateRef")
|
||||||
val updateLocalRefFunction = importRtFunction("UpdateLocalRef")
|
|
||||||
val updateGlobalRefFunction = importRtFunction("UpdateGlobalRef")
|
|
||||||
val leaveFrameFunction = importRtFunction("LeaveFrame")
|
val leaveFrameFunction = importRtFunction("LeaveFrame")
|
||||||
val setArrayFunction = importRtFunction("Kotlin_Array_set")
|
|
||||||
val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl")
|
|
||||||
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
|
||||||
val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod")
|
val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod")
|
||||||
val isInstanceFunction = importRtFunction("IsInstance")
|
val isInstanceFunction = importRtFunction("IsInstance")
|
||||||
val checkInstanceFunction = importRtFunction("CheckInstance")
|
val checkInstanceFunction = importRtFunction("CheckInstance")
|
||||||
|
|||||||
+1
-2
@@ -642,9 +642,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val bbCurrent = codegen.currentBlock
|
val bbCurrent = codegen.currentBlock
|
||||||
val bbInit = codegen.basicBlock("label_init")
|
val bbInit = codegen.basicBlock("label_init")
|
||||||
val bbExit = codegen.basicBlock("label_continue")
|
val bbExit = codegen.basicBlock("label_continue")
|
||||||
val onePtr = codegen.intToPtr(kImmInt64One, codegen.kObjHeaderPtr)
|
|
||||||
val objectVal = codegen.loadSlot(objectPtr, false)
|
val objectVal = codegen.loadSlot(objectPtr, false)
|
||||||
val condition = codegen.ucmpGt(objectVal, onePtr)
|
val condition = codegen.icmpNe(objectVal, codegen.kNullObjHeaderPtr)
|
||||||
codegen.condBr(condition, bbExit, bbInit)
|
codegen.condBr(condition, bbExit, bbInit)
|
||||||
|
|
||||||
codegen.positionAtEnd(bbInit)
|
codegen.positionAtEnd(bbInit)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) {
|
|||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
if (static_cast<uint32_t>(index) >= array->count_) {
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
UpdateGlobalRef(ArrayAddressOfElementAt(array, index), value);
|
UpdateRef(ArrayAddressOfElementAt(array, index), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_Array_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_Array_getArrayLength(KConstRef thiz) {
|
||||||
@@ -71,7 +71,7 @@ void Kotlin_Array_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KRef value)
|
|||||||
ThrowArrayIndexOutOfBoundsException();
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
for (KInt index = fromIndex; index < toIndex; ++index) {
|
for (KInt index = fromIndex; index < toIndex; ++index) {
|
||||||
UpdateGlobalRef(ArrayAddressOfElementAt(array, index), value);
|
UpdateRef(ArrayAddressOfElementAt(array, index), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,12 +86,12 @@ void Kotlin_Array_copyImpl(KConstRef thiz, KInt fromIndex,
|
|||||||
}
|
}
|
||||||
if (fromIndex >= toIndex) {
|
if (fromIndex >= toIndex) {
|
||||||
for (int index = 0; index < count; index++) {
|
for (int index = 0; index < count; index++) {
|
||||||
UpdateGlobalRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
UpdateRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
||||||
*ArrayAddressOfElementAt(array, fromIndex + index));
|
*ArrayAddressOfElementAt(array, fromIndex + index));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int index = count - 1; index >= 0; index--) {
|
for (int index = count - 1; index >= 0; index--) {
|
||||||
UpdateGlobalRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
UpdateRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
|
||||||
*ArrayAddressOfElementAt(array, fromIndex + index));
|
*ArrayAddressOfElementAt(array, fromIndex + index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-105
@@ -27,8 +27,6 @@
|
|||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
|
|
||||||
// Define to 1 to use in the multithreaded environment.
|
|
||||||
#define CONCURRENT 0
|
|
||||||
// If garbage collection algorithm for cyclic garbage to be used.
|
// If garbage collection algorithm for cyclic garbage to be used.
|
||||||
#define USE_GC 1
|
#define USE_GC 1
|
||||||
// Define to 1 to print all memory operations.
|
// Define to 1 to print all memory operations.
|
||||||
@@ -283,16 +281,15 @@ void FreeContainer(ContainerHeader* header) {
|
|||||||
for (int index = 0; index < header->objectCount_; index++) {
|
for (int index = 0; index < header->objectCount_; index++) {
|
||||||
const TypeInfo* typeInfo = obj->type_info();
|
const TypeInfo* typeInfo = obj->type_info();
|
||||||
|
|
||||||
// We use *local* versions as no other threads could see dead objects.
|
|
||||||
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
||||||
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
||||||
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]);
|
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]);
|
||||||
UpdateLocalRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
}
|
}
|
||||||
// Object arrays are *special*.
|
// Object arrays are *special*.
|
||||||
if (typeInfo == theArrayTypeInfo) {
|
if (typeInfo == theArrayTypeInfo) {
|
||||||
ArrayHeader* array = obj->array();
|
ArrayHeader* array = obj->array();
|
||||||
ReleaseLocalRefs(ArrayAddressOfElementAt(array, 0), array->count_);
|
ReleaseRefs(ArrayAddressOfElementAt(array, 0), array->count_);
|
||||||
}
|
}
|
||||||
obj = reinterpret_cast<ObjHeader*>(
|
obj = reinterpret_cast<ObjHeader*>(
|
||||||
reinterpret_cast<uintptr_t>(obj) + objectSize(obj));
|
reinterpret_cast<uintptr_t>(obj) + objectSize(obj));
|
||||||
@@ -300,10 +297,6 @@ void FreeContainer(ContainerHeader* header) {
|
|||||||
|
|
||||||
// And release underlying memory.
|
// And release underlying memory.
|
||||||
if (isFreeable(header)) {
|
if (isFreeable(header)) {
|
||||||
// TODO: atomic decrement in concurrent case.
|
|
||||||
#if CONCURRENT
|
|
||||||
#error "Atomic update of allocCount"
|
|
||||||
#endif
|
|
||||||
memoryState->allocCount--;
|
memoryState->allocCount--;
|
||||||
freeMemory(header);
|
freeMemory(header);
|
||||||
}
|
}
|
||||||
@@ -487,9 +480,6 @@ MemoryState* InitMemory() {
|
|||||||
memoryState->containers = new ContainerHeaderSet();
|
memoryState->containers = new ContainerHeaderSet();
|
||||||
#endif
|
#endif
|
||||||
#if USE_GC
|
#if USE_GC
|
||||||
#if CONCURRENT
|
|
||||||
#error "Concurrent GC is not yet implemented"
|
|
||||||
#endif
|
|
||||||
memoryState->toFree = new ContainerHeaderSet();
|
memoryState->toFree = new ContainerHeaderSet();
|
||||||
memoryState->gcInProgress = false;
|
memoryState->gcInProgress = false;
|
||||||
memoryState->gcThreshold = kGcThreshold;
|
memoryState->gcThreshold = kGcThreshold;
|
||||||
@@ -503,7 +493,7 @@ void DeinitMemory(MemoryState* memoryState) {
|
|||||||
// Free all global objects, to ensure no memory leaks happens.
|
// Free all global objects, to ensure no memory leaks happens.
|
||||||
for (auto location: *memoryState->globalObjects) {
|
for (auto location: *memoryState->globalObjects) {
|
||||||
fprintf(stderr, "Release global in *%p: %p\n", location, *location);
|
fprintf(stderr, "Release global in *%p: %p\n", location, *location);
|
||||||
UpdateGlobalRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
}
|
}
|
||||||
delete memoryState->globalObjects;
|
delete memoryState->globalObjects;
|
||||||
memoryState->globalObjects = nullptr;
|
memoryState->globalObjects = nullptr;
|
||||||
@@ -556,14 +546,7 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, uint32_t elements) {
|
|||||||
|
|
||||||
OBJ_GETTER(InitInstance,
|
OBJ_GETTER(InitInstance,
|
||||||
ObjHeader** location, const TypeInfo* type_info, void (*ctor)(ObjHeader*)) {
|
ObjHeader** location, const TypeInfo* type_info, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader* sentinel = reinterpret_cast<ObjHeader*>(1);
|
ObjHeader* value = *location;
|
||||||
ObjHeader* value;
|
|
||||||
// Wait until other initializers.
|
|
||||||
// TODO: check CONCURRENT!
|
|
||||||
while ((value = __sync_val_compare_and_swap(
|
|
||||||
location, nullptr, sentinel)) == sentinel) {
|
|
||||||
// TODO: consider yielding.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
// OK'ish, inited by someone else.
|
// OK'ish, inited by someone else.
|
||||||
@@ -571,26 +554,23 @@ OBJ_GETTER(InitInstance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjHeader* object = AllocInstance(type_info, OBJ_RESULT);
|
ObjHeader* object = AllocInstance(type_info, OBJ_RESULT);
|
||||||
UpdateGlobalRef(location, object);
|
UpdateRef(location, object);
|
||||||
try {
|
try {
|
||||||
ctor(object);
|
ctor(object);
|
||||||
#if CONCURRENT
|
|
||||||
// TODO: locking or smth lock-free in MT case?
|
|
||||||
#endif
|
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
memoryState->globalObjects->push_back(location);
|
memoryState->globalObjects->push_back(location);
|
||||||
#endif
|
#endif
|
||||||
return object;
|
return object;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
UpdateLocalRef(OBJ_RESULT, nullptr);
|
UpdateRef(OBJ_RESULT, nullptr);
|
||||||
UpdateGlobalRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLocalRef(ObjHeader** location, const ObjHeader* object) {
|
void SetRef(ObjHeader** location, const ObjHeader* object) {
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
fprintf(stderr, "SetLocalRef *%p: %p\n", location, object);
|
fprintf(stderr, "SetRef *%p: %p\n", location, object);
|
||||||
#endif
|
#endif
|
||||||
*const_cast<const ObjHeader**>(location) = object;
|
*const_cast<const ObjHeader**>(location) = object;
|
||||||
if (object != nullptr) {
|
if (object != nullptr) {
|
||||||
@@ -598,19 +578,6 @@ void SetLocalRef(ObjHeader** location, const ObjHeader* object) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetGlobalRef(ObjHeader** location, const ObjHeader* object) {
|
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "SetGlobalRef *%p: %p\n", location, object);
|
|
||||||
#endif
|
|
||||||
*const_cast<const ObjHeader**>(location) = object;
|
|
||||||
if (object != nullptr) {
|
|
||||||
AddRef(object);
|
|
||||||
}
|
|
||||||
#if CONCURRENT
|
|
||||||
// TODO: memory fence here.
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
|
void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
|
||||||
if (isArenaSlot(returnSlot)) return;
|
if (isArenaSlot(returnSlot)) return;
|
||||||
ObjHeader* old = *returnSlot;
|
ObjHeader* old = *returnSlot;
|
||||||
@@ -628,11 +595,11 @@ void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateLocalRef(ObjHeader** location, const ObjHeader* object) {
|
void UpdateRef(ObjHeader** location, const ObjHeader* object) {
|
||||||
RuntimeAssert(!isArenaSlot(location), "must not be a slot");
|
RuntimeAssert(!isArenaSlot(location), "must not be a slot");
|
||||||
ObjHeader* old = *location;
|
ObjHeader* old = *location;
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
fprintf(stderr, "UpdateLocalRef *%p: %p -> %p\n", location, old, object);
|
fprintf(stderr, "UpdateRef *%p: %p -> %p\n", location, old, object);
|
||||||
#endif
|
#endif
|
||||||
if (old != object) {
|
if (old != object) {
|
||||||
if (object != nullptr) {
|
if (object != nullptr) {
|
||||||
@@ -645,39 +612,11 @@ void UpdateLocalRef(ObjHeader** location, const ObjHeader* object) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object) {
|
|
||||||
RuntimeAssert(!isArenaSlot(location), "Must not be an arena");
|
|
||||||
#if CONCURRENT
|
|
||||||
ObjHeader* old = *location;
|
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "UpdateGlobalRef *%p: %p -> %p\n", location, old, object);
|
|
||||||
#endif
|
|
||||||
if (old != object) {
|
|
||||||
if (object != nullptr) {
|
|
||||||
AddRef(object);
|
|
||||||
}
|
|
||||||
bool written = __sync_bool_compare_and_swap(
|
|
||||||
location, old, const_cast<ObjHeader*>(object));
|
|
||||||
if (written) {
|
|
||||||
if (old > reinterpret_cast<ObjHeader*>(1)) {
|
|
||||||
ReleaseRef(old);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (object != nullptr) {
|
|
||||||
ReleaseRef(object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
UpdateLocalRef(location, object);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void LeaveFrame(ObjHeader** start, int count) {
|
void LeaveFrame(ObjHeader** start, int count) {
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
fprintf(stderr, "LeaveFrame %p .. %p\n", start, start + count);
|
fprintf(stderr, "LeaveFrame %p .. %p\n", start, start + count);
|
||||||
#endif
|
#endif
|
||||||
ReleaseLocalRefs(start + 1, count - 1);
|
ReleaseRefs(start + 1, count - 1);
|
||||||
if (*start != nullptr) {
|
if (*start != nullptr) {
|
||||||
auto arena = initedArena(start);
|
auto arena = initedArena(start);
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
@@ -688,9 +627,9 @@ void LeaveFrame(ObjHeader** start, int count) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseLocalRefs(ObjHeader** start, int count) {
|
void ReleaseRefs(ObjHeader** start, int count) {
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
fprintf(stderr, "ReleaseLocalRefs %p .. %p\n", start, start + count);
|
fprintf(stderr, "ReleaseRefs %p .. %p\n", start, start + count);
|
||||||
#endif
|
#endif
|
||||||
ObjHeader** current = start;
|
ObjHeader** current = start;
|
||||||
while (count-- > 0) {
|
while (count-- > 0) {
|
||||||
@@ -704,36 +643,6 @@ void ReleaseLocalRefs(ObjHeader** start, int count) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseGlobalRefs(ObjHeader** start, int count) {
|
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "ReleaseGlobalRefs %p .. %p\n", start, start + count);
|
|
||||||
#endif
|
|
||||||
#if CONCURRENT
|
|
||||||
ObjHeader** current = start;
|
|
||||||
while (count-- > 0) {
|
|
||||||
ObjHeader* object = *current;
|
|
||||||
if (object != nullptr) {
|
|
||||||
bool written = __sync_bool_compare_and_swap(
|
|
||||||
current, object, nullptr);
|
|
||||||
if (written)
|
|
||||||
ReleaseRef(object);
|
|
||||||
}
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
ObjHeader** current = start;
|
|
||||||
while (count-- > 0) {
|
|
||||||
ObjHeader* object = *current;
|
|
||||||
if (object != nullptr) {
|
|
||||||
ReleaseRef(object);
|
|
||||||
// Usually required.
|
|
||||||
*current = nullptr;
|
|
||||||
}
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if USE_GC
|
#if USE_GC
|
||||||
void GarbageCollect() {
|
void GarbageCollect() {
|
||||||
RuntimeAssert(memoryState->toFree != nullptr, "GC must not be stopped");
|
RuntimeAssert(memoryState->toFree != nullptr, "GC must not be stopped");
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
// Container is normal thread local container.
|
// Container is normal thread local container.
|
||||||
CONTAINER_TAG_NORMAL = 0,
|
CONTAINER_TAG_NORMAL = 0,
|
||||||
// Container shall be atomically refcounted.
|
// Container shall be atomically refcounted, currently disabled.
|
||||||
CONTAINER_TAG_SHARED = 1,
|
// CONTAINER_TAG_SHARED = 1,
|
||||||
// Those container tags shall not be refcounted.
|
// Those container tags shall not be refcounted.
|
||||||
// Permanent object, cannot refer to non-permanent objects, so no need to cleanup those.
|
// Permanent object, cannot refer to non-permanent objects, so no need to cleanup those.
|
||||||
CONTAINER_TAG_PERMANENT = 2,
|
CONTAINER_TAG_PERMANENT = 2,
|
||||||
@@ -142,9 +142,6 @@ inline void AddRef(ContainerHeader* header) {
|
|||||||
case CONTAINER_TAG_NORMAL:
|
case CONTAINER_TAG_NORMAL:
|
||||||
header->refCount_ += CONTAINER_TAG_INCREMENT;
|
header->refCount_ += CONTAINER_TAG_INCREMENT;
|
||||||
break;
|
break;
|
||||||
case CONTAINER_TAG_SHARED:
|
|
||||||
__sync_fetch_and_add(&header->refCount_, CONTAINER_TAG_INCREMENT);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
RuntimeAssert(false, "unknown container type");
|
RuntimeAssert(false, "unknown container type");
|
||||||
break;
|
break;
|
||||||
@@ -167,26 +164,6 @@ inline bool Release(ContainerHeader* header) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Note that shared containers have potentially subtle race, if object holds a
|
|
||||||
// reference to another object, stored in shorter living container. In this
|
|
||||||
// case there's unlikely, but possible case, where one mutator takes reference,
|
|
||||||
// from the field, but not yet AddRef'ed it, while another mutator updates
|
|
||||||
// field with another value, and thus Release's same field.
|
|
||||||
// If those two updates happens concurrently - it may lead to dereference of stale
|
|
||||||
// pointer.
|
|
||||||
// It seems not a very big issue as:
|
|
||||||
// - if objects stored in the same container, race will never happen
|
|
||||||
// - if concurrent field access is under lock, race will never happen
|
|
||||||
// - container likely groups multiple objects, so object release will lead to
|
|
||||||
// container release only in relatively few cases, which will decrease race
|
|
||||||
// probability even further.
|
|
||||||
case CONTAINER_TAG_SHARED:
|
|
||||||
if (__sync_sub_and_fetch(
|
|
||||||
&header->refCount_, CONTAINER_TAG_INCREMENT) == CONTAINER_TAG_SHARED) {
|
|
||||||
FreeContainer(header);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
RuntimeAssert(false, "unknown container type");
|
RuntimeAssert(false, "unknown container type");
|
||||||
break;
|
break;
|
||||||
@@ -364,18 +341,14 @@ OBJ_GETTER(InitInstance, ObjHeader** location, const TypeInfo* type_info,
|
|||||||
// in intermediate frames when throwing
|
// in intermediate frames when throwing
|
||||||
//
|
//
|
||||||
|
|
||||||
// Sets locally visible location.
|
// Sets location.
|
||||||
void SetLocalRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
void SetRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
||||||
// Sets potentially globally visible location.
|
// Updates location.
|
||||||
void SetGlobalRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
void UpdateRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
||||||
// Update locally visible location.
|
// Updates reference in return slot.
|
||||||
void UpdateLocalRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
|
||||||
// Update potentially globally visible location.
|
|
||||||
void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
|
|
||||||
// Update reference in return slot.
|
|
||||||
void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) RUNTIME_NOTHROW;
|
void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) RUNTIME_NOTHROW;
|
||||||
// Optimization: release all references in range.
|
// Optimization: release all references in range.
|
||||||
void ReleaseLocalRefs(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
void ReleaseRefs(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
||||||
// Called on frame leave, if it has object slots.
|
// Called on frame leave, if it has object slots.
|
||||||
void LeaveFrame(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
void LeaveFrame(ObjHeader** start, int count) RUNTIME_NOTHROW;
|
||||||
// Collect garbage, which cannot be found by reference counting (cycles).
|
// Collect garbage, which cannot be found by reference counting (cycles).
|
||||||
@@ -391,10 +364,10 @@ class ObjHolder {
|
|||||||
ObjHolder() : obj_(nullptr) {}
|
ObjHolder() : obj_(nullptr) {}
|
||||||
|
|
||||||
explicit ObjHolder(const ObjHeader* obj) {
|
explicit ObjHolder(const ObjHeader* obj) {
|
||||||
::SetLocalRef(&obj_, obj);
|
::SetRef(&obj_, obj);
|
||||||
}
|
}
|
||||||
~ObjHolder() {
|
~ObjHolder() {
|
||||||
::UpdateLocalRef(&obj_, nullptr);
|
::UpdateRef(&obj_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjHeader* obj() { return obj_; }
|
ObjHeader* obj() { return obj_; }
|
||||||
|
|||||||
Reference in New Issue
Block a user