mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-27 16:02:16 +00:00
more
This commit is contained in:
parent
6f70826e45
commit
e38f627c8b
@ -6602,7 +6602,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make a static array if possible
|
// make a static array if possible
|
||||||
if (isStatic) return this.ensureStaticArray(elementType, constantValues);
|
// if (isStatic) return this.ensureStaticArray(elementType, constantValues); // TODO
|
||||||
|
|
||||||
// otherwise obtain the array type
|
// otherwise obtain the array type
|
||||||
var arrayPrototype = assert(this.program.arrayPrototype);
|
var arrayPrototype = assert(this.program.arrayPrototype);
|
||||||
|
@ -33,7 +33,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
var oldData = this.data;
|
var oldData = this.data;
|
||||||
var oldCapacity = oldData.byteLength >>> alignof<T>();
|
var oldCapacity = oldData.byteLength >>> alignof<T>();
|
||||||
if (<u32>length > <u32>oldCapacity) {
|
if (<u32>length > <u32>oldCapacity) {
|
||||||
const MAX_LENGTH = ArrayBuffer.MAX_BYTELENGTH >>> alignof<T>();
|
const MAX_LENGTH = ArrayBufferView.MAX_BYTELENGTH >>> alignof<T>();
|
||||||
if (<u32>length > <u32>MAX_LENGTH) throw new RangeError("Invalid array length");
|
if (<u32>length > <u32>MAX_LENGTH) throw new RangeError("Invalid array length");
|
||||||
let newCapacity = <usize>length << alignof<T>();
|
let newCapacity = <usize>length << alignof<T>();
|
||||||
let newData = REALLOC(changetype<usize>(oldData), newCapacity); // registers on move
|
let newData = REALLOC(changetype<usize>(oldData), newCapacity); // registers on move
|
||||||
@ -373,140 +373,150 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: refactor into multiple functions?
|
|
||||||
join(separator: string = ","): string {
|
join(separator: string = ","): string {
|
||||||
|
if (isInteger<T>()) {
|
||||||
|
if (value instanceof bool) return this.join_bool(separator);
|
||||||
|
return this.join_int(separator);
|
||||||
|
}
|
||||||
|
if (isFloat<T>()) return this.join_flt(separator);
|
||||||
|
if (isString<T>()) return this.join_str(separator);
|
||||||
|
if (isArray<T>()) return this.join_arr(separator);
|
||||||
|
if (isReference<T>()) return this.join_ref(separator);
|
||||||
|
ERROR("unspported element type");
|
||||||
|
return <string>unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private join_bool(separator: string = ","): string {
|
||||||
var lastIndex = this.length_ - 1;
|
var lastIndex = this.length_ - 1;
|
||||||
if (lastIndex < 0) return "";
|
if (lastIndex < 0) return "";
|
||||||
var result = "";
|
var dataStart = this.dataStart;
|
||||||
var value: T;
|
if (!lastIndex) return select("true", "false", load<bool>(dataStart));
|
||||||
var base = this.dataStart;
|
|
||||||
// var buffer = this.buffer_;
|
|
||||||
var sepLen = separator.length;
|
|
||||||
var hasSeparator = sepLen != 0;
|
|
||||||
if (value instanceof bool) {
|
|
||||||
if (!lastIndex) return select("true", "false", load<T>(base));
|
|
||||||
|
|
||||||
let valueLen = 5; // max possible length of element len("false")
|
var sepLen = separator.length;
|
||||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
var valueLen = 5; // max possible length of element len("false")
|
||||||
let result = ALLOC(estLen << 1);
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
let offset = 0;
|
var result = ALLOC(estLen << 1);
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
var offset = 0;
|
||||||
value = load<T>(base + i);
|
var value: bool;
|
||||||
valueLen = 4 + <i32>(!value);
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
memory.copy(
|
value = load<bool>(dataStart + i);
|
||||||
result + (<usize>offset << 1),
|
|
||||||
changetype<usize>(select("true", "false", value)),
|
|
||||||
<usize>valueLen << 1
|
|
||||||
);
|
|
||||||
offset += valueLen;
|
|
||||||
if (hasSeparator) {
|
|
||||||
memory.copy(
|
|
||||||
result + (<usize>offset << 1),
|
|
||||||
changetype<usize>(separator),
|
|
||||||
<usize>sepLen << 1
|
|
||||||
);
|
|
||||||
offset += sepLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = load<T>(base + <usize>lastIndex);
|
|
||||||
valueLen = 4 + <i32>(!value);
|
valueLen = 4 + <i32>(!value);
|
||||||
memory.copy(
|
memory.copy(
|
||||||
result + (<usize>offset << 1),
|
result + (<usize>offset << 1),
|
||||||
changetype<usize>(select("true", "false", value)),
|
changetype<usize>(select("true", "false", value)),
|
||||||
valueLen << 1
|
<usize>valueLen << 1
|
||||||
);
|
);
|
||||||
offset += valueLen;
|
offset += valueLen;
|
||||||
|
if (sepLen) {
|
||||||
if (estLen > offset) {
|
memory.copy(
|
||||||
let trimmed = changetype<string>(result).substring(0, offset);
|
result + (<usize>offset << 1),
|
||||||
FREE(result);
|
changetype<usize>(separator),
|
||||||
return trimmed; // registered in .substring
|
<usize>sepLen << 1
|
||||||
|
);
|
||||||
|
offset += sepLen;
|
||||||
}
|
}
|
||||||
return REGISTER<string>(result);
|
}
|
||||||
} else if (isInteger<T>()) {
|
value = load<bool>(dataStart + <usize>lastIndex);
|
||||||
if (!lastIndex) return changetype<string>(itoa<T>(load<T>(base)));
|
valueLen = 4 + <i32>(!value);
|
||||||
|
memory.copy(
|
||||||
|
result + (<usize>offset << 1),
|
||||||
|
changetype<usize>(select("true", "false", value)),
|
||||||
|
valueLen << 1
|
||||||
|
);
|
||||||
|
offset += valueLen;
|
||||||
|
|
||||||
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + <i32>isSigned<T>();
|
if (estLen > offset) {
|
||||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
let trimmed = changetype<string>(result).substring(0, offset);
|
||||||
let result = ALLOC(estLen << 1);
|
FREE(result);
|
||||||
let offset = 0;
|
return trimmed; // registered in .substring
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
}
|
||||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
return REGISTER<string>(result);
|
||||||
offset += itoa_stream<T>(result, offset, value);
|
}
|
||||||
if (hasSeparator) {
|
|
||||||
memory.copy(
|
private join_int(separator: string = ","): string {
|
||||||
result + (<usize>offset << 1),
|
var lastIndex = this.length_ - 1;
|
||||||
changetype<usize>(separator),
|
if (lastIndex < 0) return "";
|
||||||
<usize>sepLen << 1
|
var dataStart = this.dataStart;
|
||||||
);
|
if (!lastIndex) return changetype<string>(itoa<T>(load<T>(dataStart)));
|
||||||
offset += sepLen;
|
|
||||||
}
|
var sepLen = separator.length;
|
||||||
}
|
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + <i32>isSigned<T>();
|
||||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
|
var result = ALLOC(estLen << 1);
|
||||||
|
var offset = 0;
|
||||||
|
var value: T;
|
||||||
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
|
value = load<T>(dataStart + (<usize>i << alignof<T>()));
|
||||||
offset += itoa_stream<T>(result, offset, value);
|
offset += itoa_stream<T>(result, offset, value);
|
||||||
if (estLen > offset) {
|
if (sepLen) {
|
||||||
let trimmed = changetype<string>(result).substring(0, offset);
|
memory.copy(
|
||||||
FREE(result);
|
result + (<usize>offset << 1),
|
||||||
return trimmed; // registered in .substring
|
changetype<usize>(separator),
|
||||||
|
<usize>sepLen << 1
|
||||||
|
);
|
||||||
|
offset += sepLen;
|
||||||
}
|
}
|
||||||
return REGISTER<string>(result);
|
}
|
||||||
} else if (isFloat<T>()) {
|
value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||||
if (!lastIndex) return changetype<string>(dtoa(load<T>(base)));
|
offset += itoa_stream<T>(result, offset, value);
|
||||||
|
if (estLen > offset) {
|
||||||
|
let trimmed = changetype<string>(result).substring(0, offset);
|
||||||
|
FREE(result);
|
||||||
|
return trimmed; // registered in .substring
|
||||||
|
}
|
||||||
|
return REGISTER<string>(result);
|
||||||
|
}
|
||||||
|
|
||||||
const valueLen = MAX_DOUBLE_LENGTH;
|
private join_flt(separator: string = ","): string {
|
||||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
var lastIndex = this.length_ - 1;
|
||||||
let result = ALLOC(estLen << 1);
|
if (lastIndex < 0) return "";
|
||||||
let offset = 0;
|
var dataStart = this.dataStart;
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
if (!lastIndex) return changetype<string>(dtoa(load<T>(dataStart)));
|
||||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
|
||||||
offset += dtoa_stream(result, offset, value);
|
const valueLen = MAX_DOUBLE_LENGTH;
|
||||||
if (hasSeparator) {
|
var sepLen = separator.length;
|
||||||
memory.copy(
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
result + (<usize>offset << 1),
|
var result = ALLOC(estLen << 1);
|
||||||
changetype<usize>(separator),
|
var offset = 0;
|
||||||
<usize>sepLen << 1
|
var value: T;
|
||||||
);
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
offset += sepLen;
|
value = load<T>(dataStart + (<usize>i << alignof<T>()));
|
||||||
}
|
|
||||||
}
|
|
||||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
|
||||||
offset += dtoa_stream(result, offset, value);
|
offset += dtoa_stream(result, offset, value);
|
||||||
if (estLen > offset) {
|
if (sepLen) {
|
||||||
let trimmed = changetype<string>(result).substring(0, offset);
|
memory.copy(
|
||||||
FREE(result);
|
result + (<usize>offset << 1),
|
||||||
return trimmed; // registered in .substring
|
changetype<usize>(separator),
|
||||||
|
<usize>sepLen << 1
|
||||||
|
);
|
||||||
|
offset += sepLen;
|
||||||
}
|
}
|
||||||
return REGISTER<string>(result);
|
}
|
||||||
} else if (isString<T>()) {
|
value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||||
if (!lastIndex) return load<string>(base);
|
offset += dtoa_stream(result, offset, value);
|
||||||
|
if (estLen > offset) {
|
||||||
|
let trimmed = changetype<string>(result).substring(0, offset);
|
||||||
|
FREE(result);
|
||||||
|
return trimmed; // registered in .substring
|
||||||
|
}
|
||||||
|
return REGISTER<string>(result);
|
||||||
|
}
|
||||||
|
|
||||||
let estLen = 0;
|
private join_str(separator: string = ","): string {
|
||||||
for (let i = 0, len = lastIndex + 1; i < len; ++i) {
|
var lastIndex = this.length_ - 1;
|
||||||
estLen += load<string>(base + (<usize>i << alignof<T>())).length;
|
if (lastIndex < 0) return "";
|
||||||
}
|
var dataStart = this.dataStart;
|
||||||
let offset = 0;
|
if (!lastIndex) return load<string>(dataStart);
|
||||||
let result = ALLOC((estLen + sepLen * lastIndex) << 1);
|
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
var sepLen = separator.length;
|
||||||
value = load<string>(base + (<usize>i << alignof<T>()));
|
var estLen = 0;
|
||||||
if (value) {
|
for (let i = 0, len = lastIndex + 1; i < len; ++i) {
|
||||||
let valueLen = changetype<string>(value).length;
|
estLen += load<string>(dataStart + (<usize>i << alignof<T>())).length;
|
||||||
memory.copy(
|
}
|
||||||
result + (<usize>offset << 1),
|
var offset = 0;
|
||||||
changetype<usize>(value),
|
var result = ALLOC((estLen + sepLen * lastIndex) << 1);
|
||||||
<usize>valueLen << 1
|
var value: String;
|
||||||
);
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
offset += valueLen;
|
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
||||||
}
|
|
||||||
if (hasSeparator) {
|
|
||||||
memory.copy(
|
|
||||||
result + (<usize>offset << 1),
|
|
||||||
changetype<usize>(separator),
|
|
||||||
<usize>sepLen << 1
|
|
||||||
);
|
|
||||||
offset += sepLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = load<string>(base + (<usize>lastIndex << alignof<T>()));
|
|
||||||
if (value) {
|
if (value) {
|
||||||
let valueLen = changetype<string>(value).length;
|
let valueLen = changetype<string>(value).length;
|
||||||
memory.copy(
|
memory.copy(
|
||||||
@ -514,47 +524,66 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
changetype<usize>(value),
|
changetype<usize>(value),
|
||||||
<usize>valueLen << 1
|
<usize>valueLen << 1
|
||||||
);
|
);
|
||||||
|
offset += valueLen;
|
||||||
}
|
}
|
||||||
return REGISTER<string>(result);
|
if (sepLen) {
|
||||||
} else if (isArray<T>()) {
|
memory.copy(
|
||||||
if (!lastIndex) {
|
result + (<usize>offset << 1),
|
||||||
value = load<T>(base);
|
changetype<usize>(separator),
|
||||||
return value ? value.join(separator) : "";
|
<usize>sepLen << 1
|
||||||
|
);
|
||||||
|
offset += sepLen;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
}
|
||||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
value = load<string>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||||
if (value) result += value.join(separator);
|
if (value) {
|
||||||
if (hasSeparator) result += separator;
|
let valueLen = changetype<string>(value).length;
|
||||||
}
|
memory.copy(
|
||||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
result + (<usize>offset << 1),
|
||||||
|
changetype<usize>(value),
|
||||||
|
<usize>valueLen << 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return REGISTER<string>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private join_arr(separator: string = ","): string {
|
||||||
|
var lastIndex = this.length_ - 1;
|
||||||
|
if (lastIndex < 0) return "";
|
||||||
|
|
||||||
|
var result = "";
|
||||||
|
var sepLen = separator.length;
|
||||||
|
var base = this.dataStart;
|
||||||
|
var value: T;
|
||||||
|
if (!lastIndex) {
|
||||||
|
value = load<T>(base);
|
||||||
|
return value ? value.join(separator) : "";
|
||||||
|
}
|
||||||
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
|
value = load<T>(base + (<usize>i << alignof<T>()));
|
||||||
if (value) result += value.join(separator);
|
if (value) result += value.join(separator);
|
||||||
return result; // registered by concatenation (FIXME: lots of garbage)
|
if (sepLen) result += separator;
|
||||||
} else if (isReference<T>()) { // References
|
}
|
||||||
if (!lastIndex) return "[object Object]";
|
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
||||||
const valueLen = 15; // max possible length of element len("[object Object]")
|
if (value) result += value.join(separator);
|
||||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
return result; // registered by concatenation (FIXME: lots of garbage)
|
||||||
let result = ALLOC(estLen << 1);
|
}
|
||||||
let offset = 0;
|
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
private join_ref(separator: string = ","): string {
|
||||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
var lastIndex = this.length_ - 1;
|
||||||
if (value) {
|
if (lastIndex < 0) return "";
|
||||||
memory.copy(
|
var base = this.dataStart;
|
||||||
result + (<usize>offset << 1),
|
if (!lastIndex) return "[object Object]";
|
||||||
changetype<usize>("[object Object]"),
|
|
||||||
<usize>valueLen << 1
|
const valueLen = 15; // max possible length of element len("[object Object]")
|
||||||
);
|
var sepLen = separator.length;
|
||||||
offset += valueLen;
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
}
|
var result = ALLOC(estLen << 1);
|
||||||
if (hasSeparator) {
|
var offset = 0;
|
||||||
memory.copy(
|
var value: T;
|
||||||
result + (<usize>offset << 1),
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
changetype<usize>(separator),
|
value = load<T>(base + (<usize>i << alignof<T>()));
|
||||||
<usize>sepLen << 1
|
if (value) {
|
||||||
);
|
|
||||||
offset += sepLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (load<T>(base + (<usize>lastIndex << alignof<T>()))) {
|
|
||||||
memory.copy(
|
memory.copy(
|
||||||
result + (<usize>offset << 1),
|
result + (<usize>offset << 1),
|
||||||
changetype<usize>("[object Object]"),
|
changetype<usize>("[object Object]"),
|
||||||
@ -562,16 +591,29 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
);
|
);
|
||||||
offset += valueLen;
|
offset += valueLen;
|
||||||
}
|
}
|
||||||
if (estLen > offset) {
|
if (sepLen) {
|
||||||
let out = changetype<string>(result).substring(0, offset);
|
memory.copy(
|
||||||
FREE(result);
|
result + (<usize>offset << 1),
|
||||||
return out; // registered in .substring
|
changetype<usize>(separator),
|
||||||
|
<usize>sepLen << 1
|
||||||
|
);
|
||||||
|
offset += sepLen;
|
||||||
}
|
}
|
||||||
return REGISTER<string>(result);
|
|
||||||
} else {
|
|
||||||
ERROR("unspported type");
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
|
if (load<T>(base + (<usize>lastIndex << alignof<T>()))) {
|
||||||
|
memory.copy(
|
||||||
|
result + (<usize>offset << 1),
|
||||||
|
changetype<usize>("[object Object]"),
|
||||||
|
<usize>valueLen << 1
|
||||||
|
);
|
||||||
|
offset += valueLen;
|
||||||
|
}
|
||||||
|
if (estLen > offset) {
|
||||||
|
let out = changetype<string>(result).substring(0, offset);
|
||||||
|
FREE(result);
|
||||||
|
return out; // registered in .substring
|
||||||
|
}
|
||||||
|
return REGISTER<string>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline
|
@inline
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ALLOC_RAW, REGISTER, ArrayBufferBase } from "./runtime";
|
import { HEADER, ALLOC_RAW, ALLOC, REGISTER, ArrayBufferView } from "./runtime";
|
||||||
|
|
||||||
@sealed export class ArrayBuffer extends ArrayBufferBase {
|
@sealed export class ArrayBuffer {
|
||||||
|
|
||||||
@inline static isView<T>(value: T): bool {
|
@inline static isView<T>(value: T): bool {
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -20,7 +20,16 @@ import { ALLOC_RAW, REGISTER, ArrayBufferBase } from "./runtime";
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
slice(begin: i32 = 0, end: i32 = ArrayBuffer.MAX_BYTELENGTH): ArrayBuffer {
|
constructor(length: i32) {
|
||||||
|
if (<u32>length > <u32>ArrayBufferView.MAX_BYTELENGTH) throw new RangeError("Invalid array buffer length");
|
||||||
|
return REGISTER<ArrayBuffer>(ALLOC(<usize>length));
|
||||||
|
}
|
||||||
|
|
||||||
|
get byteLength(): i32 {
|
||||||
|
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
slice(begin: i32 = 0, end: i32 = ArrayBufferView.MAX_BYTELENGTH): ArrayBuffer {
|
||||||
var length = this.byteLength;
|
var length = this.byteLength;
|
||||||
begin = begin < 0 ? max(length + begin, 0) : min(begin, length);
|
begin = begin < 0 ? max(length + begin, 0) : min(begin, length);
|
||||||
end = end < 0 ? max(length + end , 0) : min(end , length);
|
end = end < 0 ? max(length + end , 0) : min(end , length);
|
||||||
|
@ -500,5 +500,3 @@ export namespace f64x2 {
|
|||||||
export namespace v8x16 {
|
export namespace v8x16 {
|
||||||
@builtin export declare function shuffle(a: v128, b: v128, l0: u8, l1: u8, l2: u8, l3: u8, l4: u8, l5: u8, l6: u8, l7: u8, l8: u8, l9: u8, l10: u8, l11: u8, l12: u8, l13: u8, l14: u8, l15: u8): v128;
|
@builtin export declare function shuffle(a: v128, b: v128, l0: u8, l1: u8, l2: u8, l3: u8, l4: u8, l5: u8, l6: u8, l7: u8, l8: u8, l9: u8, l10: u8, l11: u8, l12: u8, l13: u8, l14: u8, l15: u8): v128;
|
||||||
}
|
}
|
||||||
|
|
||||||
@builtin export declare function start(): void;
|
|
||||||
|
31
std/assembly/gc.ts
Normal file
31
std/assembly/gc.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/** Garbage collector interface. */
|
||||||
|
export namespace gc {
|
||||||
|
|
||||||
|
/** Gets the computed unique class id of a class type. */
|
||||||
|
@builtin @unsafe export declare function classId<T>(): u32;
|
||||||
|
|
||||||
|
/** Iterates reference root objects. */
|
||||||
|
@builtin @unsafe export declare function iterateRoots(fn: (ref: usize) => void): void;
|
||||||
|
|
||||||
|
/** Registers a managed object to be tracked by the garbage collector. */
|
||||||
|
@stub @unsafe export function register(ref: usize): void {
|
||||||
|
ERROR("stub: missing garbage collector");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Links a registered object with the registered object now referencing it. */
|
||||||
|
@stub @unsafe export function link(ref: usize, parentRef: usize): void {
|
||||||
|
ERROR("stub: missing garbage collector");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Marks an object as being reachable. */
|
||||||
|
@stub @unsafe export function mark(ref: usize): void {
|
||||||
|
ERROR("stub: missing garbage collector");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Performs a full garbage collection cycle. */
|
||||||
|
@stub export function collect(): void {
|
||||||
|
WARNING("stub: missing garbage collector");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: move marking into userspace using builtins like iterateFields?
|
62
std/assembly/memory.ts
Normal file
62
std/assembly/memory.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { memcmp, memmove, memset } from "./util/memory";
|
||||||
|
|
||||||
|
/** Memory manager interface. */
|
||||||
|
export namespace memory {
|
||||||
|
|
||||||
|
/** Gets the size of the memory in pages. */
|
||||||
|
@builtin export declare function size(): i32;
|
||||||
|
|
||||||
|
/** Grows the memory by the given size in pages and returns the previous size in pages. */
|
||||||
|
@builtin @unsafe export declare function grow(pages: i32): i32;
|
||||||
|
|
||||||
|
/** Fills a section in memory with the specified byte value. */
|
||||||
|
@builtin @unsafe @inline export function fill(dst: usize, c: u8, n: usize): void {
|
||||||
|
memset(dst, c, n); // fallback if "bulk-memory" isn't enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies a section of memory to another. Has move semantics. */
|
||||||
|
@builtin @unsafe @inline export function copy(dst: usize, src: usize, n: usize): void {
|
||||||
|
memmove(dst, src, n); // fallback if "bulk-memory" isn't enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initializes a memory segment. */
|
||||||
|
@unsafe export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void {
|
||||||
|
ERROR("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Drops a memory segment. */
|
||||||
|
@unsafe export function drop(segmentIndex: u32): void {
|
||||||
|
ERROR("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dynamically allocates a section of memory and returns its address. */
|
||||||
|
@stub @inline export function allocate(size: usize): usize {
|
||||||
|
ERROR("stub: missing memory manager");
|
||||||
|
return <usize>unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dynamically frees a section of memory by the previously allocated address. */
|
||||||
|
@stub @unsafe @inline export function free(ptr: usize): void {
|
||||||
|
ERROR("stub: missing memory manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resets the memory to its initial state. Arena allocator only. */
|
||||||
|
@stub @unsafe @inline export function reset(): void {
|
||||||
|
ERROR("stub: not supported by memory manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares a section of memory to another. */
|
||||||
|
@inline export function compare(vl: usize, vr: usize, n: usize): i32 {
|
||||||
|
return memcmp(vl, vr, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Repeats a section of memory at a specific address. */
|
||||||
|
@unsafe export function repeat(dst: usize, src: usize, srcLength: usize, count: usize): void {
|
||||||
|
var index: usize = 0;
|
||||||
|
var total = srcLength * count;
|
||||||
|
while (index < total) {
|
||||||
|
memory.copy(dst + index, src, srcLength);
|
||||||
|
index += srcLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,7 @@ export function bswap<T>(value: T): T {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline
|
@inline export function bswap16<T>(value: T): T {
|
||||||
export function bswap16<T>(value: T): T {
|
|
||||||
if (isInteger<T>() && sizeof<T>() <= 4) {
|
if (isInteger<T>() && sizeof<T>() <= 4) {
|
||||||
if (sizeof<T>() == 2) {
|
if (sizeof<T>() == 2) {
|
||||||
return <T>((value << 8) | ((value >> 8) & <T>0x00FF));
|
return <T>((value << 8) | ((value >> 8) & <T>0x00FF));
|
||||||
|
@ -19,7 +19,7 @@ import { AL_MASK, MAX_SIZE_32 } from "./util/allocator";
|
|||||||
// runtime will most likely change significantly once reftypes and WASM GC are a thing.
|
// runtime will most likely change significantly once reftypes and WASM GC are a thing.
|
||||||
|
|
||||||
/** Whether a GC is present or not. */
|
/** Whether a GC is present or not. */
|
||||||
@inline export const GC = isImplemented(gc.register) && isImplemented(gc.link);
|
@inline export const GC = isImplemented(gc.register);
|
||||||
|
|
||||||
/** Size of the common runtime header. */
|
/** Size of the common runtime header. */
|
||||||
@inline export const HEADER_SIZE: usize = GC
|
@inline export const HEADER_SIZE: usize = GC
|
||||||
@ -132,20 +132,9 @@ function unref(ref: usize): HEADER {
|
|||||||
if (GC) gc.link(changetype<usize>(ref), changetype<usize>(parentRef)); // tslint:disable-line
|
if (GC) gc.link(changetype<usize>(ref), changetype<usize>(parentRef)); // tslint:disable-line
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ArrayBufferBase {
|
export abstract class ArrayBufferView {
|
||||||
@lazy static readonly MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
@lazy static readonly MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
||||||
|
|
||||||
constructor(length: i32) {
|
|
||||||
if (<u32>length > <u32>ArrayBufferBase.MAX_BYTELENGTH) throw new RangeError("Invalid array buffer length");
|
|
||||||
return REGISTER<ArrayBuffer>(ALLOC(<usize>length));
|
|
||||||
}
|
|
||||||
|
|
||||||
get byteLength(): i32 {
|
|
||||||
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class ArrayBufferView {
|
|
||||||
[key: number]: number;
|
[key: number]: number;
|
||||||
|
|
||||||
@unsafe data: ArrayBuffer;
|
@unsafe data: ArrayBuffer;
|
||||||
@ -153,9 +142,8 @@ export abstract class ArrayBufferView {
|
|||||||
@unsafe dataEnd: usize;
|
@unsafe dataEnd: usize;
|
||||||
|
|
||||||
constructor(length: i32, alignLog2: i32) {
|
constructor(length: i32, alignLog2: i32) {
|
||||||
if (<u32>length > <u32>ArrayBufferBase.MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length");
|
if (<u32>length > <u32>ArrayBufferView.MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length");
|
||||||
var byteLength = length << alignLog2;
|
var buffer = new ArrayBuffer(length << alignLog2);
|
||||||
var buffer = new ArrayBuffer(byteLength);
|
|
||||||
this.data = buffer;
|
this.data = buffer;
|
||||||
this.dataStart = changetype<usize>(buffer);
|
this.dataStart = changetype<usize>(buffer);
|
||||||
this.dataEnd = changetype<usize>(buffer) + <usize>length;
|
this.dataEnd = changetype<usize>(buffer) + <usize>length;
|
||||||
@ -170,83 +158,7 @@ export abstract class ArrayBufferView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get length(): i32 {
|
get length(): i32 {
|
||||||
ERROR("not implemented");
|
ERROR("concrete implementation must provide this");
|
||||||
return unreachable();
|
return unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class StringBase {
|
|
||||||
@lazy static readonly MAX_LENGTH: i32 = (MAX_SIZE_32 - HEADER_SIZE) >> 1;
|
|
||||||
|
|
||||||
get length(): i32 {
|
|
||||||
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize >> 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
import { memcmp, memmove, memset } from "./util/memory";
|
|
||||||
|
|
||||||
export namespace memory {
|
|
||||||
@builtin export declare function size(): i32;
|
|
||||||
|
|
||||||
@builtin @unsafe export declare function grow(pages: i32): i32;
|
|
||||||
|
|
||||||
@builtin @unsafe @inline export function fill(dst: usize, c: u8, n: usize): void {
|
|
||||||
memset(dst, c, n); // fallback if "bulk-memory" isn't enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
@builtin @unsafe @inline export function copy(dst: usize, src: usize, n: usize): void {
|
|
||||||
memmove(dst, src, n); // fallback if "bulk-memory" isn't enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
@unsafe export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void {
|
|
||||||
ERROR("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@unsafe export function drop(segmentIndex: u32): void {
|
|
||||||
ERROR("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@stub @inline export function allocate(size: usize): usize {
|
|
||||||
ERROR("stub: missing memory manager");
|
|
||||||
return <usize>unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@stub @unsafe @inline export function free(ptr: usize): void {
|
|
||||||
ERROR("stub: missing memory manager");
|
|
||||||
}
|
|
||||||
|
|
||||||
@stub @unsafe @inline export function reset(): void {
|
|
||||||
ERROR("stub: not supported by memory manager");
|
|
||||||
}
|
|
||||||
|
|
||||||
@inline export function compare(vl: usize, vr: usize, n: usize): i32 {
|
|
||||||
return memcmp(vl, vr, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
@unsafe export function repeat(dst: usize, src: usize, srcLength: usize, count: usize): void {
|
|
||||||
var index: usize = 0;
|
|
||||||
var total = srcLength * count;
|
|
||||||
while (index < total) {
|
|
||||||
memory.copy(dst + index, src, srcLength);
|
|
||||||
index += srcLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace gc {
|
|
||||||
@builtin @unsafe export declare function classId<T>(): u32;
|
|
||||||
|
|
||||||
@builtin @unsafe export declare function iterateRoots(fn: (ref: usize) => void): void;
|
|
||||||
|
|
||||||
@stub @unsafe export function register(ref: usize): void {
|
|
||||||
ERROR("stub: missing garbage collector");
|
|
||||||
}
|
|
||||||
|
|
||||||
@stub @unsafe export function link(ref: usize, parentRef: usize): void {
|
|
||||||
ERROR("stub: missing garbage collector");
|
|
||||||
}
|
|
||||||
|
|
||||||
@stub export function collect(): void {
|
|
||||||
WARNING("stub: missing garbage collector");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
import {
|
import { HEADER, HEADER_SIZE, ALLOC, REGISTER, ArrayBufferView } from "./runtime";
|
||||||
ALLOC,
|
import { MAX_SIZE_32 } from "./util/allocator";
|
||||||
REGISTER,
|
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||||
StringBase
|
|
||||||
} from "./runtime";
|
|
||||||
|
|
||||||
import {
|
@sealed export abstract class String {
|
||||||
compareImpl,
|
@lazy static readonly MAX_LENGTH: i32 = (MAX_SIZE_32 - HEADER_SIZE) >> alignof<u16>();
|
||||||
parse,
|
|
||||||
CharCode,
|
|
||||||
isWhiteSpaceOrLineTerminator
|
|
||||||
} from "./util/string";
|
|
||||||
|
|
||||||
@sealed export class String extends StringBase {
|
get length(): i32 {
|
||||||
|
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Add and handle second argument
|
// TODO Add and handle second argument
|
||||||
static fromCharCode(code: i32): String {
|
static fromCharCode(code: i32): String {
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
|
/** Vector abstraction. */
|
||||||
@sealed export class V128 {
|
@sealed export class V128 {
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user