mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-26 21:21:54 +00:00
progress
This commit is contained in:
@ -7,18 +7,20 @@ import { itoa, dtoa, itoa_stream, dtoa_stream, MAX_DOUBLE_LENGTH } from "./util/
|
||||
import { idof, isArray as builtin_isArray } from "./builtins";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_EMPTYARRAY, E_HOLEYARRAY } from "./util/error";
|
||||
|
||||
/** Ensures that the given array has _at least_ the specified capacity. */
|
||||
function ensureCapacity(array: ArrayBufferView, minCapacity: i32, alignLog2: u32): void {
|
||||
if (<u32>minCapacity > <u32>array.dataLength >>> alignLog2) {
|
||||
if (<u32>minCapacity > <u32>(BLOCK_MAXSIZE >>> alignLog2)) throw new RangeError(E_INVALIDLENGTH);
|
||||
let oldData = array.data;
|
||||
let newByteLength = minCapacity << alignLog2;
|
||||
let newData = __realloc(changetype<usize>(oldData), <usize>newByteLength); // registers on move
|
||||
if (newData !== changetype<usize>(oldData)) {
|
||||
array.data = changetype<ArrayBuffer>(newData); // retains
|
||||
array.dataStart = newData;
|
||||
/** Ensures that the given array has _at least_ the specified backing size. */
|
||||
function ensureSize(array: usize, minSize: usize, alignLog2: u32): void {
|
||||
var oldCapacity = changetype<ArrayBufferView>(array).dataLength;
|
||||
if (minSize > oldCapacity >>> alignLog2) {
|
||||
if (minSize > BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
|
||||
let oldData = changetype<usize>(changetype<ArrayBufferView>(array).data);
|
||||
let newCapacity = minSize << alignLog2;
|
||||
let newData = __realloc(oldData, newCapacity);
|
||||
memory.fill(newData + oldCapacity, 0, newCapacity - oldCapacity);
|
||||
if (newData !== oldData) { // oldData has been free'd
|
||||
store<usize>(changetype<usize>(array), __retain(newData), offsetof<ArrayBufferView>("data"));
|
||||
changetype<ArrayBufferView>(array).dataStart = newData;
|
||||
}
|
||||
array.dataLength = newByteLength;
|
||||
changetype<ArrayBufferView>(array).dataLength = <u32>newCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,10 +43,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
static create<T>(capacity: i32 = 0): Array<T> {
|
||||
if (<u32>capacity > <u32>BLOCK_MAXSIZE >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
var array = __allocArray(capacity, alignof<T>(), idof<T[]>());
|
||||
var array = changetype<Array<T>>(__allocArray(capacity, alignof<T>(), idof<T[]>())); // retains
|
||||
changetype<Array<T>>(array).length_ = 0; // safe even if T is a non-nullable reference
|
||||
memory.fill(changetype<ArrayBufferView>(array).dataStart, 0, changetype<ArrayBufferView>(array).dataLength);
|
||||
return changetype<Array<T>>(array); // retains
|
||||
memory.fill(array.dataStart, 0, <usize>array.dataLength);
|
||||
return array;
|
||||
}
|
||||
|
||||
constructor(length: i32 = 0) {
|
||||
@ -71,7 +73,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
if (<u32>length > <u32>this.length_) throw new Error(E_HOLEYARRAY);
|
||||
}
|
||||
}
|
||||
ensureCapacity(this, length, alignof<T>());
|
||||
ensureSize(changetype<usize>(this), length, alignof<T>());
|
||||
this.length_ = length;
|
||||
}
|
||||
|
||||
@ -110,7 +112,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
if (<u32>index > <u32>length) throw new Error(E_HOLEYARRAY);
|
||||
}
|
||||
}
|
||||
ensureCapacity(this, index + 1, alignof<T>());
|
||||
ensureSize(changetype<usize>(this), index + 1, alignof<T>());
|
||||
this.__unchecked_set(index, value);
|
||||
if (index >= length) this.length_ = index + 1;
|
||||
}
|
||||
@ -177,7 +179,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
push(value: T): i32 {
|
||||
var length = this.length_;
|
||||
var newLength = length + 1;
|
||||
ensureCapacity(this, newLength, alignof<T>());
|
||||
ensureSize(changetype<usize>(this), newLength, alignof<T>());
|
||||
if (isManaged<T>()) {
|
||||
let offset = this.dataStart + (<usize>length << alignof<T>());
|
||||
store<usize>(offset, __retainRelease(changetype<usize>(value), load<usize>(offset)));
|
||||
@ -193,8 +195,8 @@ export class Array<T> extends ArrayBufferView {
|
||||
var otherLen = select(0, other.length_, other === null);
|
||||
var outLen = thisLen + otherLen;
|
||||
if (<u32>outLen > <u32>BLOCK_MAXSIZE >>> alignof<T>()) throw new Error(E_INVALIDLENGTH);
|
||||
var out = __allocArray(outLen, alignof<T>(), idof<Array<T>>());
|
||||
var outStart = changetype<ArrayBufferView>(out).dataStart;
|
||||
var out = changetype<Array<T>>(__allocArray(outLen, alignof<T>(), idof<Array<T>>())); // retains
|
||||
var outStart = out.dataStart;
|
||||
var thisSize = <usize>thisLen << alignof<T>();
|
||||
if (isManaged<T>()) {
|
||||
let thisStart = this.dataStart;
|
||||
@ -213,7 +215,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
memory.copy(outStart, this.dataStart, thisSize);
|
||||
memory.copy(outStart + thisSize, other.dataStart, <usize>otherLen << alignof<T>());
|
||||
}
|
||||
return changetype<Array<T>>(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
copyWithin(target: i32, start: i32, end: i32 = i32.MAX_VALUE): this {
|
||||
@ -259,8 +261,8 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
map<U>(callbackfn: (value: T, index: i32, array: Array<T>) => U): Array<U> {
|
||||
var length = this.length_;
|
||||
var out = __allocArray(length, alignof<U>(), idof<Array<U>>());
|
||||
var outStart = changetype<ArrayBufferView>(out).dataStart;
|
||||
var out = changetype<Array<U>>(__allocArray(length, alignof<U>(), idof<Array<U>>())); // retains
|
||||
var outStart = out.dataStart;
|
||||
for (let index = 0; index < min(length, this.length_); ++index) {
|
||||
let result = callbackfn(load<T>(this.dataStart + (<usize>index << alignof<T>())), index, this); // retains
|
||||
if (isManaged<U>()) {
|
||||
@ -270,16 +272,16 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
// releases result
|
||||
}
|
||||
return changetype<Array<U>>(out); // retains
|
||||
return out;
|
||||
}
|
||||
|
||||
filter(callbackfn: (value: T, index: i32, array: Array<T>) => bool): Array<T> {
|
||||
var result = __allocArray(0, alignof<T>(), idof<Array<T>>());
|
||||
var result = changetype<Array<T>>(__allocArray(0, alignof<T>(), idof<Array<T>>())); // retains
|
||||
for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) {
|
||||
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
|
||||
if (callbackfn(value, index, this)) changetype<Array<T>>(result).push(value);
|
||||
if (callbackfn(value, index, this)) result.push(value);
|
||||
}
|
||||
return changetype<Array<T>>(result); // retains
|
||||
return result;
|
||||
}
|
||||
|
||||
reduce<U>(
|
||||
@ -332,7 +334,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
unshift(element: T): i32 {
|
||||
var newLength = this.length_ + 1;
|
||||
ensureCapacity(this, newLength, alignof<T>());
|
||||
ensureSize(changetype<usize>(this), newLength, alignof<T>());
|
||||
var dataStart = this.dataStart;
|
||||
memory.copy(
|
||||
dataStart + sizeof<T>(),
|
||||
@ -353,8 +355,8 @@ export class Array<T> extends ArrayBufferView {
|
||||
begin = begin < 0 ? max(begin + length, 0) : min(begin, length);
|
||||
end = end < 0 ? max(end + length, 0) : min(end , length);
|
||||
length = max(end - begin, 0);
|
||||
var slice = __allocArray(length, alignof<T>(), idof<Array<T>>());
|
||||
var sliceBase = changetype<ArrayBufferView>(slice).dataStart;
|
||||
var slice = changetype<Array<T>>(__allocArray(length, alignof<T>(), idof<Array<T>>())); // retains
|
||||
var sliceBase = slice.dataStart;
|
||||
var thisBase = this.dataStart + (<usize>begin << alignof<T>());
|
||||
if (isManaged<T>()) {
|
||||
let off = <usize>0;
|
||||
@ -367,15 +369,15 @@ export class Array<T> extends ArrayBufferView {
|
||||
} else {
|
||||
memory.copy(sliceBase, thisBase, length << alignof<T>());
|
||||
}
|
||||
return changetype<Array<T>>(slice); // retains
|
||||
return slice;
|
||||
}
|
||||
|
||||
splice(start: i32, deleteCount: i32 = i32.MAX_VALUE): Array<T> {
|
||||
var length = this.length_;
|
||||
start = start < 0 ? max<i32>(length + start, 0) : min<i32>(start, length);
|
||||
deleteCount = max<i32>(min<i32>(deleteCount, length - start), 0);
|
||||
var result = __allocArray(deleteCount, alignof<T>(), idof<Array<T>>());
|
||||
var resultStart = changetype<ArrayBufferView>(result).dataStart;
|
||||
var result = changetype<Array<T>>(__allocArray(deleteCount, alignof<T>(), idof<Array<T>>())); // retains
|
||||
var resultStart = result.dataStart;
|
||||
var thisStart = this.dataStart;
|
||||
var thisBase = thisStart + (<usize>start << alignof<T>());
|
||||
if (isManaged<T>()) {
|
||||
@ -401,7 +403,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
);
|
||||
}
|
||||
this.length_ = length - deleteCount;
|
||||
return changetype<Array<T>>(result); // retains
|
||||
return result;
|
||||
}
|
||||
|
||||
reverse(): Array<T> {
|
||||
@ -421,9 +423,6 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
|
||||
sort(comparator: (a: T, b: T) => i32 = COMPARATOR<T>()): this {
|
||||
// TODO remove this when flow will allow tracking null
|
||||
assert(comparator); // The comparison function must be a function
|
||||
|
||||
var length = this.length_;
|
||||
if (length <= 1) return this;
|
||||
var base = this.dataStart;
|
||||
@ -460,21 +459,21 @@ export class Array<T> extends ArrayBufferView {
|
||||
var sepLen = separator.length;
|
||||
var valueLen = 5; // max possible length of element len("false")
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = __alloc(estLen << 1, idof<string>());
|
||||
var result = changetype<string>(__alloc(estLen << 1, idof<string>())); // retains
|
||||
var offset = 0;
|
||||
var value: bool;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<bool>(dataStart + i);
|
||||
valueLen = 4 + i32(!value);
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(select("true", "false", value)),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
@ -484,16 +483,14 @@ export class Array<T> extends ArrayBufferView {
|
||||
value = load<bool>(dataStart + <usize>lastIndex);
|
||||
valueLen = 4 + i32(!value);
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(select("true", "false", value)),
|
||||
valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
|
||||
if (estLen > offset) {
|
||||
return changetype<string>(result).substring(0, offset); // retains/releases result, retains return
|
||||
}
|
||||
return changetype<string>(result); // retains
|
||||
if (estLen > offset) return result.substring(0, offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
private join_int(separator: string = ","): string {
|
||||
@ -506,16 +503,16 @@ export class Array<T> extends ArrayBufferView {
|
||||
var sepLen = separator.length;
|
||||
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + i32(isSigned<T>());
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = __alloc(estLen << 1, idof<string>());
|
||||
var result = changetype<string>(__alloc(estLen << 1, idof<string>())); // retains
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(dataStart + (<usize>i << alignof<T>()));
|
||||
// @ts-ignore: type
|
||||
offset += itoa_stream<T>(result, offset, value);
|
||||
offset += itoa_stream<T>(changetype<usize>(result), offset, value);
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
@ -524,11 +521,9 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||
// @ts-ignore: type
|
||||
offset += itoa_stream<T>(result, offset, value);
|
||||
if (estLen > offset) {
|
||||
return changetype<string>(result).substring(0, offset); // retains/releases result, retains return
|
||||
}
|
||||
return changetype<string>(result); // retains
|
||||
offset += itoa_stream<T>(changetype<usize>(result), offset, value);
|
||||
if (estLen > offset) return result.substring(0, offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
private join_flt(separator: string = ","): string {
|
||||
@ -545,18 +540,18 @@ export class Array<T> extends ArrayBufferView {
|
||||
const valueLen = MAX_DOUBLE_LENGTH;
|
||||
var sepLen = separator.length;
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = __alloc(estLen << 1, idof<string>());
|
||||
var result = changetype<string>(__alloc(estLen << 1, idof<string>())); // retains
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(dataStart + (<usize>i << alignof<T>()));
|
||||
offset += dtoa_stream(result, offset,
|
||||
offset += dtoa_stream(changetype<usize>(result), offset,
|
||||
// @ts-ignore: type
|
||||
value
|
||||
);
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
@ -564,14 +559,12 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
}
|
||||
value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||
offset += dtoa_stream(result, offset,
|
||||
offset += dtoa_stream(changetype<usize>(result), offset,
|
||||
// @ts-ignore: type
|
||||
value
|
||||
);
|
||||
if (estLen > offset) {
|
||||
return changetype<string>(result).substring(0, offset); // retains/releases result, retains return
|
||||
}
|
||||
return changetype<string>(result); // retains
|
||||
if (estLen > offset) return result.substring(0, offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
private join_str(separator: string = ","): string {
|
||||
@ -588,13 +581,13 @@ export class Array<T> extends ArrayBufferView {
|
||||
if (value !== null) estLen += value.length;
|
||||
}
|
||||
var offset = 0;
|
||||
var result = __alloc((estLen + sepLen * lastIndex) << 1, idof<string>());
|
||||
var result = changetype<string>(__alloc((estLen + sepLen * lastIndex) << 1, idof<string>())); // retains
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
||||
if (value !== null) {
|
||||
let valueLen = changetype<string>(value).length;
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(value),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
@ -602,7 +595,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
@ -612,12 +605,12 @@ export class Array<T> extends ArrayBufferView {
|
||||
value = load<string>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||
if (value !== null) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(value),
|
||||
<usize>changetype<string>(value).length << 1
|
||||
);
|
||||
}
|
||||
return changetype<string>(result); // retains
|
||||
return result;
|
||||
}
|
||||
|
||||
private join_arr(separator: string = ","): string {
|
||||
@ -654,14 +647,14 @@ export class Array<T> extends ArrayBufferView {
|
||||
const valueLen = 15; // max possible length of element len("[object Object]")
|
||||
var sepLen = separator.length;
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = __alloc(estLen << 1, idof<string>());
|
||||
var result = changetype<string>(__alloc(estLen << 1, idof<string>()));
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
||||
if (value) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>("[object Object]"),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
@ -669,7 +662,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
@ -678,42 +671,32 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
if (load<T>(base + (<usize>lastIndex << alignof<T>()))) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(result) + (<usize>offset << 1),
|
||||
changetype<usize>("[object Object]"),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
}
|
||||
if (estLen > offset) {
|
||||
return changetype<string>(result).substring(0, offset); // retains/releases result, retains return
|
||||
}
|
||||
return changetype<string>(result); // retains
|
||||
if (estLen > offset) return result.substring(0, offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.join();
|
||||
}
|
||||
|
||||
// GC integration
|
||||
// RT integration
|
||||
|
||||
@unsafe private __traverse(cookie: u32): void {
|
||||
__visit(changetype<usize>(this.data), cookie);
|
||||
@unsafe private __visit_impl(cookie: u32): void {
|
||||
if (isManaged<T>()) {
|
||||
let cur = this.dataStart;
|
||||
let end = cur + <usize>this.dataLength;
|
||||
while (cur < end) {
|
||||
let val = load<usize>(cur);
|
||||
if (isNullable<T>()) {
|
||||
if (val) {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
} else {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
if (val) __visit(val, cookie);
|
||||
cur += sizeof<usize>();
|
||||
}
|
||||
}
|
||||
// automatically visits ArrayBufferView (.data) next
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ export abstract class ArrayBufferView {
|
||||
|
||||
protected constructor(length: i32, alignLog2: i32) {
|
||||
if (<u32>length > <u32>BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = new ArrayBuffer(length = length << alignLog2);
|
||||
this.data = buffer; // retains
|
||||
this.dataStart = changetype<usize>(buffer);
|
||||
var buffer = __alloc(length = length << alignLog2, idof<ArrayBuffer>());
|
||||
this.data = changetype<ArrayBuffer>(buffer); // retains
|
||||
this.dataStart = buffer;
|
||||
this.dataLength = length;
|
||||
}
|
||||
|
||||
|
@ -56,23 +56,15 @@ export class FixedArray<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// GC integration
|
||||
// RT integration
|
||||
|
||||
@unsafe private __traverse(cookie: u32): void {
|
||||
@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 (isNullable<T>()) {
|
||||
if (val) {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
} else {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
if (val) __visit(val, cookie);
|
||||
cur += sizeof<usize>();
|
||||
}
|
||||
}
|
||||
|
@ -187,14 +187,13 @@ export class Map<K,V> {
|
||||
return "[object Map]";
|
||||
}
|
||||
|
||||
// GC integration
|
||||
// RT integration
|
||||
|
||||
@unsafe private __traverse(cookie: u32): void {
|
||||
@unsafe private __visit_impl(cookie: u32): void {
|
||||
__visit(changetype<usize>(this.buckets), cookie);
|
||||
var entries = this.entries;
|
||||
__visit(changetype<usize>(entries), cookie);
|
||||
var entries = changetype<usize>(this.entries);
|
||||
if (isManaged<K>() || isManaged<V>()) {
|
||||
let cur = changetype<usize>(entries);
|
||||
let cur = entries;
|
||||
let end = cur + <usize>this.entriesOffset * ENTRY_SIZE<K,V>();
|
||||
while (cur < end) {
|
||||
let entry = changetype<MapEntry<K,V>>(cur);
|
||||
@ -202,30 +201,19 @@ export class Map<K,V> {
|
||||
if (isManaged<K>()) {
|
||||
let val = changetype<usize>(entry.key);
|
||||
if (isNullable<K>()) {
|
||||
if (val) {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
} else {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
if (val) __visit(val, cookie);
|
||||
} else __visit(val, cookie);
|
||||
}
|
||||
if (isManaged<V>()) {
|
||||
let val = changetype<usize>(entry.value);
|
||||
if (isNullable<V>()) {
|
||||
if (val) {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
} else {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
if (val) __visit(val, cookie);
|
||||
} else __visit(val, cookie);
|
||||
}
|
||||
}
|
||||
cur += ENTRY_SIZE<K,V>();
|
||||
}
|
||||
}
|
||||
__visit(entries, cookie);
|
||||
}
|
||||
}
|
||||
|
@ -46,14 +46,14 @@
|
||||
|
||||
import { RTTI_BASE } from "builtins";
|
||||
import { RTTIData, RTTIFlags } from "common/rtti";
|
||||
import { E_INDEXOUTOFRANGE } from "../util/error";
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __typeinfo(id: u32): RTTIFlags {
|
||||
var ptr = RTTI_BASE;
|
||||
return !id || id > load<u32>(ptr)
|
||||
? unreachable()
|
||||
: changetype<RTTIData>(ptr + id * offsetof<RTTIData>()).flags;
|
||||
if (!id || id > load<u32>(ptr)) throw new Error(E_INDEXOUTOFRANGE);
|
||||
return changetype<RTTIData>(ptr + id * offsetof<RTTIData>()).flags;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@ -79,7 +79,7 @@ export function __allocArray(length: i32, alignLog2: usize, id: u32, data: usize
|
||||
var array = __alloc(offsetof<i32[]>(), id);
|
||||
var bufferSize = <usize>length << alignLog2;
|
||||
var buffer = __alloc(bufferSize, idof<ArrayBuffer>());
|
||||
changetype<ArrayBufferView>(array).data = changetype<ArrayBuffer>(buffer); // TODO/RT: retains
|
||||
store<usize>(array, __retain(buffer), offsetof<ArrayBufferView>("data"));
|
||||
changetype<ArrayBufferView>(array).dataStart = buffer;
|
||||
changetype<ArrayBufferView>(array).dataLength = bufferSize;
|
||||
store<i32>(changetype<usize>(array), length, offsetof<i32[]>("length_"));
|
||||
|
@ -1,85 +1,2 @@
|
||||
import { AL_MASK, BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "rt/common";
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
var startOffset: usize = (HEAP_BASE + AL_MASK) & ~AL_MASK;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
var offset: usize = startOffset;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __alloc(size: usize, id: u32): usize {
|
||||
if (size > BLOCK_MAXSIZE) unreachable();
|
||||
var ptr = offset + BLOCK_OVERHEAD;
|
||||
var newPtr = (ptr + max<usize>(size, 1) + AL_MASK) & ~AL_MASK;
|
||||
var pagesBefore = memory.size();
|
||||
if (newPtr > <usize>pagesBefore << 16) {
|
||||
let pagesNeeded = ((newPtr - ptr + 0xffff) & ~0xffff) >>> 16;
|
||||
let pagesWanted = max(pagesBefore, pagesNeeded); // double memory
|
||||
if (memory.grow(pagesWanted) < 0) {
|
||||
if (memory.grow(pagesNeeded) < 0) unreachable(); // out of memory
|
||||
}
|
||||
}
|
||||
offset = newPtr;
|
||||
var block = changetype<BLOCK>(ptr - BLOCK_OVERHEAD);
|
||||
block.rtId = id;
|
||||
block.rtSize = size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __realloc(ref: usize, size: usize): usize {
|
||||
var block = changetype<BLOCK>(ref - BLOCK_OVERHEAD);
|
||||
var oldSize = <usize>block.rtSize;
|
||||
if (size > oldSize) {
|
||||
let newRef = __alloc(size, block.rtId);
|
||||
memory.copy(newRef, ref, oldSize);
|
||||
ref = newRef;
|
||||
} else {
|
||||
block.rtSize = size;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __free(ref: usize): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
// @unsafe @global
|
||||
// export function __reset(): void { // special
|
||||
// offset = startOffset;
|
||||
// }
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
export function __retain(ref: usize): usize {
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
export function __release(ref: usize): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
function __visit(ref: usize, cookie: u32): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
function __retainRelease(ref: usize, oldRef: usize): usize {
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
export function __collect(): void {
|
||||
}
|
||||
|
||||
export { __alloc, __realloc, __free, __retain, __release, __collect } from "rt/stub";
|
||||
export { __instanceof, __typeinfo } from "rt/common";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DEBUG, BLOCK_OVERHEAD, BLOCK } from "rt/common";
|
||||
import { DEBUG, BLOCK_OVERHEAD } from "rt/common";
|
||||
import { Block, freeBlock, ROOT } from "rt/tlsf";
|
||||
import { RTTIFlags } from "common/rtti";
|
||||
|
||||
@ -102,12 +102,16 @@ function increment(s: Block): void {
|
||||
var info = s.gcInfo;
|
||||
assert((info & ~REFCOUNT_MASK) == ((info + 1) & ~REFCOUNT_MASK)); // overflow
|
||||
s.gcInfo = info + 1;
|
||||
if (isDefined(ASC_RTRACE)) onIncrement(s);
|
||||
if (DEBUG) assert(!(s.mmInfo & 1)); // used
|
||||
}
|
||||
|
||||
/** Decrements the reference count of the specified block by one, possibly freeing it. */
|
||||
function decrement(s: Block): void {
|
||||
var info = s.gcInfo;
|
||||
var rc = info & REFCOUNT_MASK;
|
||||
if (isDefined(ASC_RTRACE)) onDecrement(s);
|
||||
if (DEBUG) assert(!(s.mmInfo & 1)); // used
|
||||
if (rc == 1) {
|
||||
__visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_DECREMENT);
|
||||
if (!(info & BUFFERED_MASK)) {
|
||||
@ -261,3 +265,11 @@ export function __retainRelease(ref: usize, oldRef: usize): usize {
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@external("rtrace", "retain")
|
||||
declare function onIncrement(s: Block): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@external("rtrace", "release")
|
||||
declare function onDecrement(s: Block): void;
|
||||
|
83
std/assembly/rt/stub.ts
Normal file
83
std/assembly/rt/stub.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { AL_MASK, BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "rt/common";
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
var startOffset: usize = (HEAP_BASE + AL_MASK) & ~AL_MASK;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
var offset: usize = startOffset;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __alloc(size: usize, id: u32): usize {
|
||||
if (size > BLOCK_MAXSIZE) unreachable();
|
||||
var ptr = offset + BLOCK_OVERHEAD;
|
||||
var newPtr = (ptr + max<usize>(size, 1) + AL_MASK) & ~AL_MASK;
|
||||
var pagesBefore = memory.size();
|
||||
if (newPtr > <usize>pagesBefore << 16) {
|
||||
let pagesNeeded = ((newPtr - ptr + 0xffff) & ~0xffff) >>> 16;
|
||||
let pagesWanted = max(pagesBefore, pagesNeeded); // double memory
|
||||
if (memory.grow(pagesWanted) < 0) {
|
||||
if (memory.grow(pagesNeeded) < 0) unreachable(); // out of memory
|
||||
}
|
||||
}
|
||||
offset = newPtr;
|
||||
var block = changetype<BLOCK>(ptr - BLOCK_OVERHEAD);
|
||||
block.rtId = id;
|
||||
block.rtSize = size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __realloc(ref: usize, size: usize): usize {
|
||||
var block = changetype<BLOCK>(ref - BLOCK_OVERHEAD);
|
||||
var oldSize = <usize>block.rtSize;
|
||||
if (size > oldSize) {
|
||||
let newRef = __alloc(size, block.rtId);
|
||||
memory.copy(newRef, ref, oldSize);
|
||||
ref = newRef;
|
||||
} else {
|
||||
block.rtSize = size;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @global
|
||||
export function __free(ref: usize): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
// @unsafe @global
|
||||
// export function __reset(): void { // special
|
||||
// offset = startOffset;
|
||||
// }
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
export function __retain(ref: usize): usize {
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
export function __release(ref: usize): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
function __visit(ref: usize, cookie: u32): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
function __retainRelease(ref: usize, oldRef: usize): usize {
|
||||
return ref;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
export function __collect(): void {
|
||||
}
|
@ -476,7 +476,7 @@ export function allocateBlock(root: Root, size: usize): Block {
|
||||
if (DEBUG) assert(block); // must be found now
|
||||
}
|
||||
if (DEBUG) assert((block.mmInfo & ~TAGS_MASK) >= payloadSize); // must fit
|
||||
block.gcInfo = 1; // RC=1
|
||||
block.gcInfo = 0; // RC=0
|
||||
// block.rtId = 0; // set by the caller (__alloc)
|
||||
block.rtSize = size;
|
||||
removeBlock(root, <Block>block);
|
||||
@ -520,6 +520,7 @@ export function reallocateBlock(root: Root, block: Block, size: usize): Block {
|
||||
memory.copy(changetype<usize>(newBlock) + BLOCK_OVERHEAD, changetype<usize>(block) + BLOCK_OVERHEAD, size);
|
||||
block.mmInfo = blockInfo | FREE;
|
||||
insertBlock(root, block);
|
||||
if (isDefined(ASC_RTRACE)) onFree(block);
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
@ -529,6 +530,7 @@ export function freeBlock(root: Root, block: Block): void {
|
||||
assert(!(blockInfo & FREE)); // must be used (user might call through to this)
|
||||
block.mmInfo = blockInfo | FREE;
|
||||
insertBlock(root, block);
|
||||
if (isDefined(ASC_RTRACE)) onFree(block);
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@ -559,3 +561,7 @@ export function __free(ref: usize): void {
|
||||
assert(ref != 0 && !(ref & AL_MASK)); // must exist and be aligned
|
||||
freeBlock(ROOT, changetype<Block>(ref - BLOCK_OVERHEAD));
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@external("rtrace", "free")
|
||||
declare function onFree(s: Block): void;
|
||||
|
@ -167,31 +167,25 @@ export class Set<K> {
|
||||
return "[object Set]";
|
||||
}
|
||||
|
||||
// GC integration
|
||||
// RT integration
|
||||
|
||||
@unsafe private __traverse(cookie: u32): void {
|
||||
@unsafe private __visit_impl(cookie: u32): void {
|
||||
__visit(changetype<usize>(this.buckets), cookie);
|
||||
var entries = this.entries;
|
||||
__visit(changetype<usize>(entries), cookie);
|
||||
var entries = changetype<usize>(this.entries);
|
||||
if (isManaged<K>()) {
|
||||
let cur = changetype<usize>(entries);
|
||||
let cur = entries;
|
||||
let end = cur + <usize>this.entriesOffset * ENTRY_SIZE<K>();
|
||||
while (cur < end) {
|
||||
let entry = changetype<SetEntry<K>>(cur);
|
||||
if (!(entry.taggedNext & EMPTY)) {
|
||||
let val = changetype<usize>(entry.key);
|
||||
if (isNullable<K>()) {
|
||||
if (val) {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
} else {
|
||||
__visit(val, cookie);
|
||||
__visit_members(val, cookie);
|
||||
}
|
||||
if (val) __visit(val, cookie);
|
||||
} else __visit(val, cookie);
|
||||
}
|
||||
cur += ENTRY_SIZE<K>();
|
||||
}
|
||||
}
|
||||
__visit(entries, cookie);
|
||||
}
|
||||
}
|
||||
|
@ -68,10 +68,10 @@ import { idof } from "./builtins";
|
||||
var otherSize: isize = other.length << 1;
|
||||
var outSize: usize = thisSize + otherSize;
|
||||
if (outSize == 0) return changetype<String>("");
|
||||
var out = __alloc(outSize, idof<String>());
|
||||
memory.copy(out, changetype<usize>(this), thisSize);
|
||||
memory.copy(out + thisSize, changetype<usize>(other), otherSize);
|
||||
return changetype<String>(out); // retains
|
||||
var out = changetype<String>(__alloc(outSize, idof<String>())); // retains
|
||||
memory.copy(changetype<usize>(out), changetype<usize>(this), thisSize);
|
||||
memory.copy(changetype<usize>(out) + thisSize, changetype<usize>(other), otherSize);
|
||||
return out;
|
||||
}
|
||||
|
||||
endsWith(searchString: String, endPosition: i32 = String.MAX_LENGTH): bool {
|
||||
|
Reference in New Issue
Block a user