This commit is contained in:
dcode 2019-03-13 22:35:47 +01:00
parent 6f70826e45
commit e38f627c8b
10 changed files with 326 additions and 276 deletions

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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
View 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
View 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;
}
}
}

View File

@ -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));

View File

@ -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");
}
}

View File

@ -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 {

View File

@ -1,2 +1,3 @@
/** Vector abstraction. */
@sealed export class V128 { @sealed export class V128 {
} }