mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-20 10:16:37 +00:00
Implement reference counting (#592)
This commit is contained in:
72
std/assembly/fixedarray.ts
Normal file
72
std/assembly/fixedarray.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/// <reference path="./rt/index.d.ts" />
|
||||
|
||||
import { BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "./rt/common";
|
||||
import { idof } from "./builtins";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
|
||||
|
||||
// NOTE: DO NOT USE YET!
|
||||
|
||||
// TODO: FixedArray<T,S> with S being the static size, i.e. `new FixedArray<i32,10>`.
|
||||
// Then hard-wire this special type to the compiler and do static length checks instead :)
|
||||
|
||||
export class FixedArray<T> {
|
||||
[key: number]: T;
|
||||
|
||||
constructor(length: i32) {
|
||||
if (<u32>length > <u32>BLOCK_MAXSIZE >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (isReference<T>()) {
|
||||
if (!isNullable<T>()) {
|
||||
if (length) throw new Error(E_HOLEYARRAY);
|
||||
}
|
||||
}
|
||||
var outSize = <usize>length << alignof<T>();
|
||||
var out = __alloc(outSize, idof<FixedArray<T>>());
|
||||
memory.fill(out, 0, outSize);
|
||||
return changetype<FixedArray<T>>(out); // retains
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
return changetype<BLOCK>(changetype<usize>(this) - BLOCK_OVERHEAD).rtSize >>> alignof<T>();
|
||||
}
|
||||
|
||||
@operator("[]") private __get(index: i32): T {
|
||||
if (<u32>index >= <u32>this.length) throw new RangeError(E_INDEXOUTOFRANGE);
|
||||
return this.__unchecked_get(index);
|
||||
}
|
||||
|
||||
@operator("[]=") private __set(index: i32, value: T): void {
|
||||
if (<u32>index >= <u32>this.length) throw new RangeError(E_INDEXOUTOFRANGE);
|
||||
this.__unchecked_set(index, value);
|
||||
}
|
||||
|
||||
@operator("{}") private __unchecked_get(index: i32): T {
|
||||
return load<T>(changetype<usize>(this) + (<usize>index << alignof<T>()));
|
||||
}
|
||||
|
||||
@operator("{}=") private __unchecked_set(index: i32, value: T): void {
|
||||
if (isManaged<T>()) {
|
||||
let offset = changetype<usize>(this) + (<usize>index << alignof<T>());
|
||||
let oldValue = load<usize>(offset);
|
||||
if (changetype<usize>(value) != oldValue) {
|
||||
store<usize>(offset, __retain(changetype<usize>(value)));
|
||||
__release(changetype<usize>(oldValue));
|
||||
}
|
||||
} else {
|
||||
store<T>(changetype<usize>(this) + (<usize>index << alignof<T>()), value);
|
||||
}
|
||||
}
|
||||
|
||||
// RT integration
|
||||
|
||||
@unsafe private __visit_impl(cookie: u32): void {
|
||||
if (isManaged<T>()) {
|
||||
let cur = changetype<usize>(this);
|
||||
let end = cur + changetype<BLOCK>(changetype<usize>(this) - BLOCK_OVERHEAD).rtSize;
|
||||
while (cur < end) {
|
||||
let val = load<usize>(cur);
|
||||
if (val) __visit(val, cookie);
|
||||
cur += sizeof<usize>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user