From 15182f1315b2f2e44b4af2765fd6b922a2a49414 Mon Sep 17 00:00:00 2001 From: Sebastian Baginski Date: Thu, 14 Jul 2016 10:17:25 +0200 Subject: [PATCH 1/5] support for custom allocator in ByteBuffer --- base.use | 1 + source/base/Allocator.ooc | 18 ++++++++++++++++++ source/base/ByteBuffer.ooc | 17 +++++++++++------ test/base/ByteBufferTest.ooc | 20 ++++++++++++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 source/base/Allocator.ooc diff --git a/base.use b/base.use index 7c74b6e36..2c71de8fc 100644 --- a/base.use +++ b/base.use @@ -2,6 +2,7 @@ Name: Base Description: Base library that complements the built-in SDK. SourcePath: source/base Imports: Order +Imports: Allocator Imports: ByteBuffer Imports: DateTime Imports: TimeSpan diff --git a/source/base/Allocator.ooc b/source/base/Allocator.ooc new file mode 100644 index 000000000..f3491d533 --- /dev/null +++ b/source/base/Allocator.ooc @@ -0,0 +1,18 @@ +/* This file is part of magic-sdk, an sdk for the open source programming language magic. + * + * Copyright (C) 2016 magic-lang + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +AbstractAllocator: abstract class { + allocate: abstract func (size: SizeT) -> Void* + deallocate: abstract func (pointer: Void*) +} + +MallocAllocator: class extends AbstractAllocator { + init: func + allocate: override func (size: SizeT) -> Void* { malloc(size) } + deallocate: override func (pointer: Void*) { memfree(pointer) } +} diff --git a/source/base/ByteBuffer.ooc b/source/base/ByteBuffer.ooc index 07f00e511..e0d082c96 100644 --- a/source/base/ByteBuffer.ooc +++ b/source/base/ByteBuffer.ooc @@ -7,6 +7,7 @@ */ use collections +import Allocator import ReferenceCounter import Debug @@ -15,21 +16,24 @@ ByteBuffer: class { _size: Int _referenceCount: ReferenceCounter _ownsMemory: Bool + _allocator: AbstractAllocator = null pointer ::= this _pointer size ::= this _size referenceCount ::= this _referenceCount - init: func (=_pointer, =_size, ownsMemory := false) { + init: func (=_pointer, =_size, ownsMemory := false, allocator := null as AbstractAllocator) { this _referenceCount = ReferenceCounter new(this) this _ownsMemory = ownsMemory + this _allocator = allocator ?? MallocAllocator new() as AbstractAllocator } free: override func { if (this _referenceCount != null) this _referenceCount free() this _referenceCount = null if (this _ownsMemory) - memfree(this _pointer) + this _allocator deallocate(this _pointer) this _pointer = null + this _allocator free() super() } zero: func ~whole { this memset(0) } @@ -50,7 +54,7 @@ ByteBuffer: class { copyTo: func (other: This, start: Int, destination: Int, length: Int) { memcpy(other pointer + destination, this pointer + start, length) } - new: static func ~size (size: Int) -> This { _RecyclableByteBuffer new(size) } + new: static func ~size (size: Int, allocator: AbstractAllocator = null) -> This { _RecyclableByteBuffer new(size, allocator) } new: static func ~recover (pointer: Byte*, size: Int, recover: Func (This) -> Bool) -> This { _RecoverableByteBuffer new(pointer, size, recover) } @@ -86,7 +90,7 @@ _RecoverableByteBuffer: class extends ByteBuffer { } _RecyclableByteBuffer: class extends ByteBuffer { - init: func (pointer: Byte*, size: Int) { super(pointer, size, true) } + init: func (pointer: Byte*, size: Int, allocator: AbstractAllocator = null) { super(pointer, size, true, allocator) } _forceFree: func { this _size = 0 this free() @@ -111,7 +115,7 @@ _RecyclableByteBuffer: class extends ByteBuffer { _smallRecycleBin := static VectorList new() _mediumRecycleBin := static VectorList new() _largeRecycleBin := static VectorList new() - new: static func ~fromSize (size: Int) -> This { + new: static func ~fromSize (size: Int, allocator: AbstractAllocator = null) -> This { buffer: This = null bin := This _getBin(size) This _lock lock() @@ -123,7 +127,8 @@ _RecyclableByteBuffer: class extends ByteBuffer { } This _lock unlock() version(debugByteBuffer) { if (buffer == null) Debug print("No RecyclableByteBuffer available in the bin; allocating a new one") } - buffer == null ? This new(malloc(size), size) : buffer + allocator = allocator ?? MallocAllocator new() as AbstractAllocator + buffer == null ? This new(allocator allocate(size) as Byte*, size, allocator) : buffer } _getBin: static func (size: Int) -> VectorList { size < 10000 ? This _smallRecycleBin : (size < 100000 ? This _mediumRecycleBin : This _largeRecycleBin) diff --git a/test/base/ByteBufferTest.ooc b/test/base/ByteBufferTest.ooc index 6adc6ae6c..3f8e94307 100644 --- a/test/base/ByteBufferTest.ooc +++ b/test/base/ByteBufferTest.ooc @@ -9,6 +9,18 @@ use base use unit +CustomAllocator: class extends AbstractAllocator { + _allocCount := 0 + init: func + allocate: override func (size: SizeT) -> Void* { + this _allocCount += 1 + malloc(size) + } + deallocate: override func (pointer: Void*) { + memfree(pointer) + } +} + ByteBufferTest: class extends Fixture { init: func { super("ByteBuffer") @@ -78,6 +90,14 @@ ByteBufferTest: class extends Fixture { expect(buffer pointer[63] as Int, is equal to(63)) buffer referenceCount decrease() }) + this add("custom alloc", This _testCustomAlloc) + } + _testCustomAlloc: static func { + allocator := CustomAllocator new() + expect(allocator _allocCount, is equal to(0)) + buffer := ByteBuffer new(128, allocator) + expect(allocator _allocCount, is equal to(1)) + buffer free() } } From a7779bdaa6141d3e287734ddb4b1c44ecd1a54ff Mon Sep 17 00:00:00 2001 From: Sebastian Baginski Date: Thu, 14 Jul 2016 11:34:58 +0200 Subject: [PATCH 2/5] owner flag for allocator --- source/base/Allocator.ooc | 9 ++++++++- source/base/ByteBuffer.ooc | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/source/base/Allocator.ooc b/source/base/Allocator.ooc index f3491d533..c53283708 100644 --- a/source/base/Allocator.ooc +++ b/source/base/Allocator.ooc @@ -6,13 +6,20 @@ * of the MIT license. See the LICENSE file for details. */ +import Owner + AbstractAllocator: abstract class { + _owner: Owner + free: func ~withCriteria (owner: Owner) { + if (owner == this _owner) + this free() + } allocate: abstract func (size: SizeT) -> Void* deallocate: abstract func (pointer: Void*) } MallocAllocator: class extends AbstractAllocator { - init: func + init: func (owner := Owner Receiver) { this _owner = owner } allocate: override func (size: SizeT) -> Void* { malloc(size) } deallocate: override func (pointer: Void*) { memfree(pointer) } } diff --git a/source/base/ByteBuffer.ooc b/source/base/ByteBuffer.ooc index e0d082c96..f0e70f9b0 100644 --- a/source/base/ByteBuffer.ooc +++ b/source/base/ByteBuffer.ooc @@ -33,7 +33,7 @@ ByteBuffer: class { if (this _ownsMemory) this _allocator deallocate(this _pointer) this _pointer = null - this _allocator free() + this _allocator free(Owner Receiver) super() } zero: func ~whole { this memset(0) } From 15c9692e231ca1cc587aec4654fb8ff75091ee9f Mon Sep 17 00:00:00 2001 From: Sebastian Baginski Date: Thu, 14 Jul 2016 11:41:23 +0200 Subject: [PATCH 3/5] changed pointer to pointer --- source/base/Allocator.ooc | 8 ++++---- test/base/ByteBufferTest.ooc | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/base/Allocator.ooc b/source/base/Allocator.ooc index c53283708..0bb134c52 100644 --- a/source/base/Allocator.ooc +++ b/source/base/Allocator.ooc @@ -14,12 +14,12 @@ AbstractAllocator: abstract class { if (owner == this _owner) this free() } - allocate: abstract func (size: SizeT) -> Void* - deallocate: abstract func (pointer: Void*) + allocate: abstract func (size: SizeT) -> Pointer + deallocate: abstract func (pointer: Pointer) } MallocAllocator: class extends AbstractAllocator { init: func (owner := Owner Receiver) { this _owner = owner } - allocate: override func (size: SizeT) -> Void* { malloc(size) } - deallocate: override func (pointer: Void*) { memfree(pointer) } + allocate: override func (size: SizeT) -> Pointer { malloc(size) } + deallocate: override func (pointer: Pointer) { memfree(pointer) } } diff --git a/test/base/ByteBufferTest.ooc b/test/base/ByteBufferTest.ooc index 3f8e94307..7ea620751 100644 --- a/test/base/ByteBufferTest.ooc +++ b/test/base/ByteBufferTest.ooc @@ -12,11 +12,11 @@ use unit CustomAllocator: class extends AbstractAllocator { _allocCount := 0 init: func - allocate: override func (size: SizeT) -> Void* { + allocate: override func (size: SizeT) -> Pointer { this _allocCount += 1 malloc(size) } - deallocate: override func (pointer: Void*) { + deallocate: override func (pointer: Pointer) { memfree(pointer) } } From 5b9a62882443cf63f024337813100a6f020c94b0 Mon Sep 17 00:00:00 2001 From: Sebastian Baginski Date: Thu, 14 Jul 2016 12:19:10 +0200 Subject: [PATCH 4/5] added default allocators to prevent allocating too many allocators --- source/base/Allocator.ooc | 11 +++++++++++ source/base/ByteBuffer.ooc | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/source/base/Allocator.ooc b/source/base/Allocator.ooc index 0bb134c52..9c1f53d0e 100644 --- a/source/base/Allocator.ooc +++ b/source/base/Allocator.ooc @@ -23,3 +23,14 @@ MallocAllocator: class extends AbstractAllocator { allocate: override func (size: SizeT) -> Pointer { malloc(size) } deallocate: override func (pointer: Pointer) { memfree(pointer) } } + +Allocator: abstract class { + _defaultAllocator: static AbstractAllocator = null + mallocAllocator := static MallocAllocator new(Owner Sender) + defaultAllocator: static func -> AbstractAllocator { + This _defaultAllocator ?? mallocAllocator as AbstractAllocator + } + free: static func ~all { + This mallocAllocator free(Owner Sender) + } +} diff --git a/source/base/ByteBuffer.ooc b/source/base/ByteBuffer.ooc index f0e70f9b0..40ecf8fef 100644 --- a/source/base/ByteBuffer.ooc +++ b/source/base/ByteBuffer.ooc @@ -16,15 +16,15 @@ ByteBuffer: class { _size: Int _referenceCount: ReferenceCounter _ownsMemory: Bool - _allocator: AbstractAllocator = null + _allocator: AbstractAllocator pointer ::= this _pointer size ::= this _size referenceCount ::= this _referenceCount - init: func (=_pointer, =_size, ownsMemory := false, allocator := null as AbstractAllocator) { + init: func (=_pointer, =_size, ownsMemory := false, allocator := Allocator defaultAllocator()) { this _referenceCount = ReferenceCounter new(this) this _ownsMemory = ownsMemory - this _allocator = allocator ?? MallocAllocator new() as AbstractAllocator + this _allocator = allocator } free: override func { if (this _referenceCount != null) @@ -54,11 +54,14 @@ ByteBuffer: class { copyTo: func (other: This, start: Int, destination: Int, length: Int) { memcpy(other pointer + destination, this pointer + start, length) } - new: static func ~size (size: Int, allocator: AbstractAllocator = null) -> This { _RecyclableByteBuffer new(size, allocator) } + new: static func ~size (size: Int, allocator := Allocator defaultAllocator()) -> This { _RecyclableByteBuffer new(size, allocator) } new: static func ~recover (pointer: Byte*, size: Int, recover: Func (This) -> Bool) -> This { _RecoverableByteBuffer new(pointer, size, recover) } - free: static func ~all { _RecyclableByteBuffer _free~all() } + free: static func ~all { + _RecyclableByteBuffer _free~all() + Allocator free~all() + } } GlobalCleanup register(|| ByteBuffer free~all(), true) @@ -90,7 +93,7 @@ _RecoverableByteBuffer: class extends ByteBuffer { } _RecyclableByteBuffer: class extends ByteBuffer { - init: func (pointer: Byte*, size: Int, allocator: AbstractAllocator = null) { super(pointer, size, true, allocator) } + init: func (pointer: Byte*, size: Int, allocator := Allocator defaultAllocator()) { super(pointer, size, true, allocator) } _forceFree: func { this _size = 0 this free() @@ -115,7 +118,7 @@ _RecyclableByteBuffer: class extends ByteBuffer { _smallRecycleBin := static VectorList new() _mediumRecycleBin := static VectorList new() _largeRecycleBin := static VectorList new() - new: static func ~fromSize (size: Int, allocator: AbstractAllocator = null) -> This { + new: static func ~fromSize (size: Int, allocator := Allocator defaultAllocator()) -> This { buffer: This = null bin := This _getBin(size) This _lock lock() @@ -127,7 +130,6 @@ _RecyclableByteBuffer: class extends ByteBuffer { } This _lock unlock() version(debugByteBuffer) { if (buffer == null) Debug print("No RecyclableByteBuffer available in the bin; allocating a new one") } - allocator = allocator ?? MallocAllocator new() as AbstractAllocator buffer == null ? This new(allocator allocate(size) as Byte*, size, allocator) : buffer } _getBin: static func (size: Int) -> VectorList { From 2518a8a5cc6e7636054ab82392c40cf4e0fbd9d9 Mon Sep 17 00:00:00 2001 From: Sebastian Baginski Date: Mon, 1 Aug 2016 08:53:54 +0200 Subject: [PATCH 5/5] updated tests --- source/base/ByteBuffer.ooc | 2 +- test/base/ByteBufferTest.ooc | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/source/base/ByteBuffer.ooc b/source/base/ByteBuffer.ooc index 40ecf8fef..1aab57ad6 100644 --- a/source/base/ByteBuffer.ooc +++ b/source/base/ByteBuffer.ooc @@ -60,11 +60,11 @@ ByteBuffer: class { } free: static func ~all { _RecyclableByteBuffer _free~all() - Allocator free~all() } } GlobalCleanup register(|| ByteBuffer free~all(), true) +GlobalCleanup register(|| Allocator free~all(), true) _SlicedByteBuffer: class extends ByteBuffer { _parent: ByteBuffer diff --git a/test/base/ByteBufferTest.ooc b/test/base/ByteBufferTest.ooc index 7ea620751..d4a1332c8 100644 --- a/test/base/ByteBufferTest.ooc +++ b/test/base/ByteBufferTest.ooc @@ -11,12 +11,14 @@ use unit CustomAllocator: class extends AbstractAllocator { _allocCount := 0 + _freeCount := static 0 init: func allocate: override func (size: SizeT) -> Pointer { this _allocCount += 1 malloc(size) } deallocate: override func (pointer: Pointer) { + This _freeCount += 1 memfree(pointer) } } @@ -97,7 +99,8 @@ ByteBufferTest: class extends Fixture { expect(allocator _allocCount, is equal to(0)) buffer := ByteBuffer new(128, allocator) expect(allocator _allocCount, is equal to(1)) - buffer free() + (buffer as _RecyclableByteBuffer) _forceFree() + expect(CustomAllocator _freeCount, is equal to(1)) } }