Skip to content

Commit

Permalink
fix(malloc): update freeAll(), add test, doc strings, minor cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Nov 7, 2019
1 parent a40c265 commit 830b267
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 16 deletions.
100 changes: 88 additions & 12 deletions packages/malloc/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { IRelease, Type, TypedArray } from "@thi.ng/api";
import {
IRelease,
Type,
TypedArray,
TypedArrayTypeMap
} from "@thi.ng/api";
import { Pow2 } from "@thi.ng/binary";

export interface MemBlock {
addr: number;
size: number;
next: MemBlock | null;
}

export interface MemPoolOpts {
/**
* Backing ArrayBuffer (or SharedArrayBuffer). If not given, a new
Expand Down Expand Up @@ -94,23 +93,100 @@ export interface MemPoolStats {
}

export interface IMemPool extends IRelease {
/**
* Attempts to allocate a new memory block of given `size` (in
* bytes). Returns block address or zero if unsuccessful
* (insufficient memory).
*
* @param size
*/
malloc(size: number): number;

calloc(size: number): number;
/**
* Similar to `malloc()`, but if allocation was successful also
* clears the allocated block w/ `fill` value (default: 0).
*
* @param size
* @param fill
*/
calloc(size: number, fill?: number): number;

mallocAs(type: Type, num: number): TypedArray | undefined;
/**
* Takes a `Type` enum and element count `num` (in units of given
* type), calls `malloc()` and if successful wraps allocated block
* as typed array of given `type`. Returns undefined if allocation
* failed.
*
* @param type
* @param num
*/
mallocAs<T extends Type>(
type: T,
num: number
): TypedArrayTypeMap[T] | undefined;

callocAs(type: Type, num: number): TypedArray | undefined;
/**
* Similar to `mallocAs()`, but if allocation was successful also
* clears the allocated block w/ `fill` value (default: 0).
*
* @param type
* @param num
* @param fill
*/
callocAs<T extends Type>(
type: T,
num: number,
fill?: number
): TypedArrayTypeMap[T] | undefined;

/**
* Attempts to reallocate given memory block to new `size` (in
* bytes). If new `size` is larger than the original, attempts to
* grow block or else allocates new one and moves contents to new
* address. If new size is smaller than original, the existing block
* might be split (depending on `split` & `minSplit` config options)
* and the unused part freed. Returns new address if successful or
* zero if re-allocation failed (insufficient menory).
*
* @param ptr
* @param size
*/
realloc(ptr: number, size: number): number;

reallocArray(arr: TypedArray, num: number): TypedArray | undefined;
/**
* Similar to `realloc()`, but takes a typed array (one previously
* allocated with `mallocAs()` or `callocAs()`) and if successul
* returns new typed array of same type. Returns undefined on
* failure.
*
* @param arr
* @param num
*/
reallocArray<T extends TypedArray>(arr: T, num: number): T | undefined;

/**
* Takes a memory block address and attempts to return the block to
* the pool. Depending on `compact` config option, this operation
* might cause compaction of consecutive free memory blocks to help
* counter fragmentation. Returns true if block has been freed.
*
* It's the user's responsibility to ensure that freed blocks are
* not used any further after calling `free()`. Undefined behavior,
* or worse, pool corruption might ensue!
*
* @param ptr
*/
free(ptr: number | TypedArray): boolean;

/**
* Frees all previously allocated blocks and resests allocator state.
*/
freeAll(): void;

stats(): MemPoolStats;
/**
* Returns an information object of the pool's state.
*/
stats(): Readonly<MemPoolStats>;
}

export type BlockCtor = (
Expand Down
10 changes: 6 additions & 4 deletions packages/malloc/src/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
TypedArray,
typedArray
} from "@thi.ng/api";
import { align, isPow2, Pow2 } from "@thi.ng/binary";
import { align, Pow2 } from "@thi.ng/binary";
import { isNumber } from "@thi.ng/checks";
import { illegalArgs } from "@thi.ng/errors";
import { IMemPool, MemPoolOpts, MemPoolStats } from "./api";
Expand Down Expand Up @@ -46,7 +46,7 @@ export class MemPool implements IMemPool {
if (!opts.skipInitialization) {
const _align = opts.align || 8;
assert(
_align >= 8 && isPow2(_align),
_align >= 8,
`invalid alignment: ${_align}, must be a pow2 and >= 8`
);
const top =
Expand Down Expand Up @@ -76,7 +76,7 @@ export class MemPool implements IMemPool {
}
}

stats(): MemPoolStats {
stats(): Readonly<MemPoolStats> {
const listStats = (block: number) => {
let count = 0;
let size = 0;
Expand Down Expand Up @@ -260,7 +260,9 @@ export class MemPool implements IMemPool {
freeAll() {
this._free = 0;
this._used = 0;
this.top = align(this.start + SIZEOF_STATE, this.align);
this.top =
align(this.start + SIZEOF_STATE + SIZEOF_MEM_BLOCK, this.align) -
SIZEOF_MEM_BLOCK;
}

release() {
Expand Down
9 changes: 9 additions & 0 deletions packages/malloc/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,13 @@ describe("malloc", () => {
assert.equal(p._used, 0);
assert.equal(p.top, base);
});

it("freeAll (align 16)", () => {
pool = new MemPool({ size: 0x100, align: 16 });
const base = pool.stats().top;
pool.callocAs(Type.U8, 15);
pool.callocAs(Type.U8, 11);
pool.freeAll();
assert.equal(pool.stats().top, base);
});
});

0 comments on commit 830b267

Please sign in to comment.