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
|
||||
if (isStatic) return this.ensureStaticArray(elementType, constantValues);
|
||||
// if (isStatic) return this.ensureStaticArray(elementType, constantValues); // TODO
|
||||
|
||||
// otherwise obtain the array type
|
||||
var arrayPrototype = assert(this.program.arrayPrototype);
|
||||
|
@ -33,7 +33,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
var oldData = this.data;
|
||||
var oldCapacity = oldData.byteLength >>> alignof<T>();
|
||||
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");
|
||||
let newCapacity = <usize>length << alignof<T>();
|
||||
let newData = REALLOC(changetype<usize>(oldData), newCapacity); // registers on move
|
||||
@ -373,140 +373,150 @@ export class Array<T> extends ArrayBufferView {
|
||||
return this;
|
||||
}
|
||||
|
||||
// FIXME: refactor into multiple functions?
|
||||
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;
|
||||
if (lastIndex < 0) return "";
|
||||
var result = "";
|
||||
var value: T;
|
||||
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));
|
||||
var dataStart = this.dataStart;
|
||||
if (!lastIndex) return select("true", "false", load<bool>(dataStart));
|
||||
|
||||
let valueLen = 5; // max possible length of element len("false")
|
||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
let result = ALLOC(estLen << 1);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(base + i);
|
||||
valueLen = 4 + <i32>(!value);
|
||||
memory.copy(
|
||||
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);
|
||||
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);
|
||||
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>(select("true", "false", value)),
|
||||
valueLen << 1
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
FREE(result);
|
||||
return trimmed; // registered in .substring
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
} else if (isInteger<T>()) {
|
||||
if (!lastIndex) return changetype<string>(itoa<T>(load<T>(base)));
|
||||
}
|
||||
value = load<bool>(dataStart + <usize>lastIndex);
|
||||
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>();
|
||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
let result = ALLOC(estLen << 1);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
||||
offset += itoa_stream<T>(result, offset, value);
|
||||
if (hasSeparator) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
}
|
||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
FREE(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
}
|
||||
|
||||
private join_int(separator: string = ","): string {
|
||||
var lastIndex = this.length_ - 1;
|
||||
if (lastIndex < 0) return "";
|
||||
var dataStart = this.dataStart;
|
||||
if (!lastIndex) return changetype<string>(itoa<T>(load<T>(dataStart)));
|
||||
|
||||
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);
|
||||
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);
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
FREE(result);
|
||||
return trimmed; // registered in .substring
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
} else if (isFloat<T>()) {
|
||||
if (!lastIndex) return changetype<string>(dtoa(load<T>(base)));
|
||||
}
|
||||
value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||
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;
|
||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
let result = ALLOC(estLen << 1);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
||||
offset += dtoa_stream(result, offset, value);
|
||||
if (hasSeparator) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
}
|
||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
||||
private join_flt(separator: string = ","): string {
|
||||
var lastIndex = this.length_ - 1;
|
||||
if (lastIndex < 0) return "";
|
||||
var dataStart = this.dataStart;
|
||||
if (!lastIndex) return changetype<string>(dtoa(load<T>(dataStart)));
|
||||
|
||||
const valueLen = MAX_DOUBLE_LENGTH;
|
||||
var sepLen = separator.length;
|
||||
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 += dtoa_stream(result, offset, value);
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
FREE(result);
|
||||
return trimmed; // registered in .substring
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
} else if (isString<T>()) {
|
||||
if (!lastIndex) return load<string>(base);
|
||||
}
|
||||
value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||
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;
|
||||
for (let i = 0, len = lastIndex + 1; i < len; ++i) {
|
||||
estLen += load<string>(base + (<usize>i << alignof<T>())).length;
|
||||
}
|
||||
let offset = 0;
|
||||
let result = ALLOC((estLen + sepLen * lastIndex) << 1);
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<string>(base + (<usize>i << alignof<T>()));
|
||||
if (value) {
|
||||
let valueLen = changetype<string>(value).length;
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(value),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
}
|
||||
if (hasSeparator) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
}
|
||||
value = load<string>(base + (<usize>lastIndex << alignof<T>()));
|
||||
private join_str(separator: string = ","): string {
|
||||
var lastIndex = this.length_ - 1;
|
||||
if (lastIndex < 0) return "";
|
||||
var dataStart = this.dataStart;
|
||||
if (!lastIndex) return load<string>(dataStart);
|
||||
|
||||
var sepLen = separator.length;
|
||||
var estLen = 0;
|
||||
for (let i = 0, len = lastIndex + 1; i < len; ++i) {
|
||||
estLen += load<string>(dataStart + (<usize>i << alignof<T>())).length;
|
||||
}
|
||||
var offset = 0;
|
||||
var result = ALLOC((estLen + sepLen * lastIndex) << 1);
|
||||
var value: String;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
||||
if (value) {
|
||||
let valueLen = changetype<string>(value).length;
|
||||
memory.copy(
|
||||
@ -514,47 +524,66 @@ export class Array<T> extends ArrayBufferView {
|
||||
changetype<usize>(value),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
} else if (isArray<T>()) {
|
||||
if (!lastIndex) {
|
||||
value = load<T>(base);
|
||||
return value ? value.join(separator) : "";
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<T>(base + (<usize>i << alignof<T>()));
|
||||
if (value) result += value.join(separator);
|
||||
if (hasSeparator) result += separator;
|
||||
}
|
||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
||||
}
|
||||
value = load<string>(dataStart + (<usize>lastIndex << alignof<T>()));
|
||||
if (value) {
|
||||
let valueLen = changetype<string>(value).length;
|
||||
memory.copy(
|
||||
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);
|
||||
return result; // registered by concatenation (FIXME: lots of garbage)
|
||||
} else if (isReference<T>()) { // References
|
||||
if (!lastIndex) return "[object Object]";
|
||||
const valueLen = 15; // max possible length of element len("[object Object]")
|
||||
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
let result = ALLOC(estLen << 1);
|
||||
let offset = 0;
|
||||
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>("[object Object]"),
|
||||
<usize>valueLen << 1
|
||||
);
|
||||
offset += valueLen;
|
||||
}
|
||||
if (hasSeparator) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
changetype<usize>(separator),
|
||||
<usize>sepLen << 1
|
||||
);
|
||||
offset += sepLen;
|
||||
}
|
||||
}
|
||||
if (load<T>(base + (<usize>lastIndex << alignof<T>()))) {
|
||||
if (sepLen) result += separator;
|
||||
}
|
||||
value = load<T>(base + (<usize>lastIndex << alignof<T>()));
|
||||
if (value) result += value.join(separator);
|
||||
return result; // registered by concatenation (FIXME: lots of garbage)
|
||||
}
|
||||
|
||||
private join_ref(separator: string = ","): string {
|
||||
var lastIndex = this.length_ - 1;
|
||||
if (lastIndex < 0) return "";
|
||||
var base = this.dataStart;
|
||||
if (!lastIndex) return "[object Object]";
|
||||
|
||||
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);
|
||||
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>("[object Object]"),
|
||||
@ -562,16 +591,29 @@ export class Array<T> extends ArrayBufferView {
|
||||
);
|
||||
offset += valueLen;
|
||||
}
|
||||
if (estLen > offset) {
|
||||
let out = changetype<string>(result).substring(0, offset);
|
||||
FREE(result);
|
||||
return out; // registered in .substring
|
||||
if (sepLen) {
|
||||
memory.copy(
|
||||
result + (<usize>offset << 1),
|
||||
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
|
||||
|
@ -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 {
|
||||
if (value) {
|
||||
@ -20,7 +20,16 @@ import { ALLOC_RAW, REGISTER, ArrayBufferBase } from "./runtime";
|
||||
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;
|
||||
begin = begin < 0 ? max(length + begin, 0) : min(begin, length);
|
||||
end = end < 0 ? max(length + end , 0) : min(end , length);
|
||||
|
@ -500,5 +500,3 @@ export namespace f64x2 {
|
||||
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 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;
|
||||
}
|
||||
|
||||
@inline
|
||||
export function bswap16<T>(value: T): T {
|
||||
@inline export function bswap16<T>(value: T): T {
|
||||
if (isInteger<T>() && sizeof<T>() <= 4) {
|
||||
if (sizeof<T>() == 2) {
|
||||
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.
|
||||
|
||||
/** 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. */
|
||||
@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
|
||||
}
|
||||
|
||||
export abstract class ArrayBufferBase {
|
||||
export abstract class ArrayBufferView {
|
||||
@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;
|
||||
|
||||
@unsafe data: ArrayBuffer;
|
||||
@ -153,9 +142,8 @@ export abstract class ArrayBufferView {
|
||||
@unsafe dataEnd: usize;
|
||||
|
||||
constructor(length: i32, alignLog2: i32) {
|
||||
if (<u32>length > <u32>ArrayBufferBase.MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length");
|
||||
var byteLength = length << alignLog2;
|
||||
var buffer = new ArrayBuffer(byteLength);
|
||||
if (<u32>length > <u32>ArrayBufferView.MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length");
|
||||
var buffer = new ArrayBuffer(length << alignLog2);
|
||||
this.data = buffer;
|
||||
this.dataStart = changetype<usize>(buffer);
|
||||
this.dataEnd = changetype<usize>(buffer) + <usize>length;
|
||||
@ -170,83 +158,7 @@ export abstract class ArrayBufferView {
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
ERROR("not implemented");
|
||||
ERROR("concrete implementation must provide this");
|
||||
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 {
|
||||
ALLOC,
|
||||
REGISTER,
|
||||
StringBase
|
||||
} from "./runtime";
|
||||
import { HEADER, HEADER_SIZE, ALLOC, REGISTER, ArrayBufferView } from "./runtime";
|
||||
import { MAX_SIZE_32 } from "./util/allocator";
|
||||
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||
|
||||
import {
|
||||
compareImpl,
|
||||
parse,
|
||||
CharCode,
|
||||
isWhiteSpaceOrLineTerminator
|
||||
} from "./util/string";
|
||||
@sealed export abstract class String {
|
||||
@lazy static readonly MAX_LENGTH: i32 = (MAX_SIZE_32 - HEADER_SIZE) >> alignof<u16>();
|
||||
|
||||
@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
|
||||
static fromCharCode(code: i32): String {
|
||||
|
@ -1,2 +1,3 @@
|
||||
/** Vector abstraction. */
|
||||
@sealed export class V128 {
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user