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,25 +373,33 @@ 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);
var offset = 0;
var value: bool;
for (let i = 0; i < lastIndex; ++i) { for (let i = 0; i < lastIndex; ++i) {
value = load<T>(base + i); value = load<bool>(dataStart + i);
valueLen = 4 + <i32>(!value); valueLen = 4 + <i32>(!value);
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
@ -399,7 +407,7 @@ export class Array<T> extends ArrayBufferView {
<usize>valueLen << 1 <usize>valueLen << 1
); );
offset += valueLen; offset += valueLen;
if (hasSeparator) { if (sepLen) {
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
changetype<usize>(separator), changetype<usize>(separator),
@ -408,7 +416,7 @@ export class Array<T> extends ArrayBufferView {
offset += sepLen; offset += sepLen;
} }
} }
value = load<T>(base + <usize>lastIndex); value = load<bool>(dataStart + <usize>lastIndex);
valueLen = 4 + <i32>(!value); valueLen = 4 + <i32>(!value);
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
@ -423,17 +431,24 @@ export class Array<T> extends ArrayBufferView {
return trimmed; // registered in .substring return trimmed; // registered in .substring
} }
return REGISTER<string>(result); return REGISTER<string>(result);
} else if (isInteger<T>()) { }
if (!lastIndex) return changetype<string>(itoa<T>(load<T>(base)));
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>(); const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + <i32>isSigned<T>();
let estLen = (valueLen + sepLen) * lastIndex + valueLen; var estLen = (valueLen + sepLen) * lastIndex + valueLen;
let result = ALLOC(estLen << 1); var result = ALLOC(estLen << 1);
let offset = 0; var offset = 0;
var value: T;
for (let i = 0; i < lastIndex; ++i) { for (let i = 0; i < lastIndex; ++i) {
value = load<T>(base + (<usize>i << alignof<T>())); value = load<T>(dataStart + (<usize>i << alignof<T>()));
offset += itoa_stream<T>(result, offset, value); offset += itoa_stream<T>(result, offset, value);
if (hasSeparator) { if (sepLen) {
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
changetype<usize>(separator), changetype<usize>(separator),
@ -442,7 +457,7 @@ export class Array<T> extends ArrayBufferView {
offset += sepLen; offset += sepLen;
} }
} }
value = load<T>(base + (<usize>lastIndex << alignof<T>())); value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
offset += itoa_stream<T>(result, offset, value); offset += itoa_stream<T>(result, offset, value);
if (estLen > offset) { if (estLen > offset) {
let trimmed = changetype<string>(result).substring(0, offset); let trimmed = changetype<string>(result).substring(0, offset);
@ -450,17 +465,24 @@ export class Array<T> extends ArrayBufferView {
return trimmed; // registered in .substring return trimmed; // registered in .substring
} }
return REGISTER<string>(result); return REGISTER<string>(result);
} else if (isFloat<T>()) { }
if (!lastIndex) return changetype<string>(dtoa(load<T>(base)));
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; const valueLen = MAX_DOUBLE_LENGTH;
let estLen = (valueLen + sepLen) * lastIndex + valueLen; var sepLen = separator.length;
let result = ALLOC(estLen << 1); var estLen = (valueLen + sepLen) * lastIndex + valueLen;
let offset = 0; var result = ALLOC(estLen << 1);
var offset = 0;
var value: T;
for (let i = 0; i < lastIndex; ++i) { for (let i = 0; i < lastIndex; ++i) {
value = load<T>(base + (<usize>i << alignof<T>())); value = load<T>(dataStart + (<usize>i << alignof<T>()));
offset += dtoa_stream(result, offset, value); offset += dtoa_stream(result, offset, value);
if (hasSeparator) { if (sepLen) {
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
changetype<usize>(separator), changetype<usize>(separator),
@ -469,7 +491,7 @@ export class Array<T> extends ArrayBufferView {
offset += sepLen; offset += sepLen;
} }
} }
value = load<T>(base + (<usize>lastIndex << alignof<T>())); value = load<T>(dataStart + (<usize>lastIndex << alignof<T>()));
offset += dtoa_stream(result, offset, value); offset += dtoa_stream(result, offset, value);
if (estLen > offset) { if (estLen > offset) {
let trimmed = changetype<string>(result).substring(0, offset); let trimmed = changetype<string>(result).substring(0, offset);
@ -477,17 +499,24 @@ export class Array<T> extends ArrayBufferView {
return trimmed; // registered in .substring return trimmed; // registered in .substring
} }
return REGISTER<string>(result); return REGISTER<string>(result);
} else if (isString<T>()) {
if (!lastIndex) return load<string>(base);
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); 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) { for (let i = 0; i < lastIndex; ++i) {
value = load<string>(base + (<usize>i << alignof<T>())); value = load<string>(dataStart + (<usize>i << alignof<T>()));
if (value) { if (value) {
let valueLen = changetype<string>(value).length; let valueLen = changetype<string>(value).length;
memory.copy( memory.copy(
@ -497,7 +526,7 @@ export class Array<T> extends ArrayBufferView {
); );
offset += valueLen; offset += valueLen;
} }
if (hasSeparator) { if (sepLen) {
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
changetype<usize>(separator), changetype<usize>(separator),
@ -506,7 +535,7 @@ export class Array<T> extends ArrayBufferView {
offset += sepLen; offset += sepLen;
} }
} }
value = load<string>(base + (<usize>lastIndex << alignof<T>())); value = load<string>(dataStart + (<usize>lastIndex << alignof<T>()));
if (value) { if (value) {
let valueLen = changetype<string>(value).length; let valueLen = changetype<string>(value).length;
memory.copy( memory.copy(
@ -516,7 +545,16 @@ export class Array<T> extends ArrayBufferView {
); );
} }
return REGISTER<string>(result); return REGISTER<string>(result);
} else if (isArray<T>()) { }
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) { if (!lastIndex) {
value = load<T>(base); value = load<T>(base);
return value ? value.join(separator) : ""; return value ? value.join(separator) : "";
@ -524,17 +562,25 @@ export class Array<T> extends ArrayBufferView {
for (let i = 0; i < lastIndex; ++i) { for (let i = 0; i < lastIndex; ++i) {
value = load<T>(base + (<usize>i << alignof<T>())); value = load<T>(base + (<usize>i << alignof<T>()));
if (value) result += value.join(separator); if (value) result += value.join(separator);
if (hasSeparator) result += separator; if (sepLen) result += separator;
} }
value = load<T>(base + (<usize>lastIndex << alignof<T>())); value = load<T>(base + (<usize>lastIndex << alignof<T>()));
if (value) result += value.join(separator); if (value) result += value.join(separator);
return result; // registered by concatenation (FIXME: lots of garbage) return result; // registered by concatenation (FIXME: lots of garbage)
} else if (isReference<T>()) { // References }
private join_ref(separator: string = ","): string {
var lastIndex = this.length_ - 1;
if (lastIndex < 0) return "";
var base = this.dataStart;
if (!lastIndex) return "[object Object]"; if (!lastIndex) return "[object Object]";
const valueLen = 15; // max possible length of element len("[object Object]") const valueLen = 15; // max possible length of element len("[object Object]")
let estLen = (valueLen + sepLen) * lastIndex + valueLen; var sepLen = separator.length;
let result = ALLOC(estLen << 1); var estLen = (valueLen + sepLen) * lastIndex + valueLen;
let offset = 0; var result = ALLOC(estLen << 1);
var offset = 0;
var value: T;
for (let i = 0; i < lastIndex; ++i) { for (let i = 0; i < lastIndex; ++i) {
value = load<T>(base + (<usize>i << alignof<T>())); value = load<T>(base + (<usize>i << alignof<T>()));
if (value) { if (value) {
@ -545,7 +591,7 @@ export class Array<T> extends ArrayBufferView {
); );
offset += valueLen; offset += valueLen;
} }
if (hasSeparator) { if (sepLen) {
memory.copy( memory.copy(
result + (<usize>offset << 1), result + (<usize>offset << 1),
changetype<usize>(separator), changetype<usize>(separator),
@ -568,10 +614,6 @@ export class Array<T> extends ArrayBufferView {
return out; // registered in .substring return out; // registered in .substring
} }
return REGISTER<string>(result); return REGISTER<string>(result);
} else {
ERROR("unspported type");
assert(false);
}
} }
@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 {
} }