mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-18 17:31:29 +00:00
some cleanup
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { ALLOCATE, REALLOCATE, DISCARD, REGISTER, MAX_BYTELENGTH, MAKEARRAY, ArrayBufferView, classId } from "./runtime";
|
||||
import { ArrayBuffer } from "./arraybuffer";
|
||||
import { runtime, classId } from "./runtime";
|
||||
import { ArrayBuffer, ArrayBufferView } from "./arraybuffer";
|
||||
import { COMPARATOR, SORT } from "./util/sort";
|
||||
import { itoa, dtoa, itoa_stream, dtoa_stream, MAX_DOUBLE_LENGTH } from "./util/number";
|
||||
import { isArray as builtin_isArray } from "./builtins";
|
||||
@ -10,10 +10,10 @@ import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_EMPTYARRAY, E_HOLEYARRAY } from "
|
||||
/** Ensures that the given array has _at least_ the specified capacity. */
|
||||
function ensureCapacity(array: ArrayBufferView, minCapacity: i32, alignLog2: u32): void {
|
||||
if (<u32>minCapacity > <u32>array.dataLength >>> alignLog2) {
|
||||
if (<u32>minCapacity > <u32>(MAX_BYTELENGTH >>> alignLog2)) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (<u32>minCapacity > <u32>(runtime.MAX_BYTELENGTH >>> alignLog2)) throw new RangeError(E_INVALIDLENGTH);
|
||||
let oldData = array.data;
|
||||
let newByteLength = minCapacity << alignLog2;
|
||||
let newData = REALLOCATE(changetype<usize>(oldData), <usize>newByteLength); // registers on move
|
||||
let newData = runtime.reallocate(changetype<usize>(oldData), <usize>newByteLength); // registers on move
|
||||
if (newData !== changetype<usize>(oldData)) {
|
||||
array.data = changetype<ArrayBuffer>(newData); // links
|
||||
array.dataStart = newData;
|
||||
@ -40,8 +40,8 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
|
||||
static create<T>(capacity: i32 = 0): Array<T> {
|
||||
if (<u32>capacity > <u32>MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
var array = MAKEARRAY<T>(capacity);
|
||||
if (<u32>capacity > <u32>runtime.MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
var array = changetype<Array<T>>(runtime.makeArray(capacity, classId<Array<T>>(), alignof<T>()));
|
||||
memory.fill(array.dataStart, 0, <usize>array.dataLength);
|
||||
array.length_ = 0; // !
|
||||
return array;
|
||||
@ -231,7 +231,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
concat(other: Array<T>): Array<T> {
|
||||
var thisLen = this.length_;
|
||||
var otherLen = select(0, other.length_, other === null);
|
||||
var out = MAKEARRAY<T>(thisLen + otherLen);
|
||||
var out = changetype<Array<T>>(runtime.makeArray(thisLen + otherLen, classId<Array<T>>(), alignof<T>()));
|
||||
var outStart = out.dataStart;
|
||||
var thisSize = <usize>thisLen << alignof<T>();
|
||||
if (isManaged<T>()) {
|
||||
@ -319,7 +319,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
map<U>(callbackfn: (value: T, index: i32, array: Array<T>) => U): Array<U> {
|
||||
var length = this.length_;
|
||||
var out = MAKEARRAY<U>(length);
|
||||
var out = changetype<Array<U>>(runtime.makeArray(length, classId<Array<U>>(), alignof<U>()));
|
||||
var outStart = out.dataStart;
|
||||
for (let index = 0; index < min(length, this.length_); ++index) {
|
||||
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
|
||||
@ -345,7 +345,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
|
||||
filter(callbackfn: (value: T, index: i32, array: Array<T>) => bool): Array<T> {
|
||||
var result = MAKEARRAY<T>(0);
|
||||
var result = changetype<Array<T>>(runtime.makeArray(0, classId<Array<T>>(), alignof<T>()));
|
||||
for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) {
|
||||
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
|
||||
if (callbackfn(value, index, this)) result.push(value);
|
||||
@ -433,7 +433,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
begin = begin < 0 ? max(begin + length, 0) : min(begin, length);
|
||||
end = end < 0 ? max(end + length, 0) : min(end , length);
|
||||
length = max(end - begin, 0);
|
||||
var slice = MAKEARRAY<T>(length);
|
||||
var slice = changetype<Array<T>>(runtime.makeArray(length, classId<Array<T>>(), alignof<T>()));
|
||||
var sliceBase = slice.dataStart;
|
||||
var thisBase = this.dataStart + (<usize>begin << alignof<T>());
|
||||
if (isManaged<T>()) {
|
||||
@ -465,7 +465,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
var length = this.length_;
|
||||
start = start < 0 ? max<i32>(length + start, 0) : min<i32>(start, length);
|
||||
deleteCount = max<i32>(min<i32>(deleteCount, length - start), 0);
|
||||
var result = MAKEARRAY<T>(deleteCount);
|
||||
var result = changetype<Array<T>>(runtime.makeArray(deleteCount, classId<Array<T>>(), alignof<T>()));
|
||||
var resultStart = result.dataStart;
|
||||
var thisStart = this.dataStart;
|
||||
var thisBase = thisStart + (<usize>start << alignof<T>());
|
||||
@ -560,7 +560,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
var sepLen = separator.length;
|
||||
var valueLen = 5; // max possible length of element len("false")
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = ALLOCATE(estLen << 1);
|
||||
var result = runtime.allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: bool;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -592,10 +592,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
DISCARD(result);
|
||||
runtime.discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
}
|
||||
|
||||
private join_int(separator: string = ","): string {
|
||||
@ -608,7 +608,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
var sepLen = separator.length;
|
||||
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + i32(isSigned<T>());
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = ALLOCATE(estLen << 1);
|
||||
var result = runtime.allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -629,10 +629,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
offset += itoa_stream<T>(result, offset, value);
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
DISCARD(result);
|
||||
runtime.discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
}
|
||||
|
||||
private join_flt(separator: string = ","): string {
|
||||
@ -649,7 +649,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
const valueLen = MAX_DOUBLE_LENGTH;
|
||||
var sepLen = separator.length;
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = ALLOCATE(estLen << 1);
|
||||
var result = runtime.allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -674,10 +674,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
);
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
DISCARD(result);
|
||||
runtime.discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
}
|
||||
|
||||
private join_str(separator: string = ","): string {
|
||||
@ -694,7 +694,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
if (value !== null) estLen += value.length;
|
||||
}
|
||||
var offset = 0;
|
||||
var result = ALLOCATE((estLen + sepLen * lastIndex) << 1);
|
||||
var result = runtime.allocate((estLen + sepLen * lastIndex) << 1);
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
||||
if (value !== null) {
|
||||
@ -723,7 +723,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
<usize>changetype<string>(value).length << 1
|
||||
);
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
}
|
||||
|
||||
private join_arr(separator: string = ","): string {
|
||||
@ -760,7 +760,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
const valueLen = 15; // max possible length of element len("[object Object]")
|
||||
var sepLen = separator.length;
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = ALLOCATE(estLen << 1);
|
||||
var result = runtime.allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -792,10 +792,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
if (estLen > offset) {
|
||||
let out = changetype<string>(result).substring(0, offset);
|
||||
DISCARD(result);
|
||||
runtime.discard(result);
|
||||
return out; // registered in .substring
|
||||
}
|
||||
return REGISTER<string>(result);
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
@ -1,6 +1,34 @@
|
||||
import { ALLOCATE, REGISTER, HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./runtime";
|
||||
import { runtime, HEADER, HEADER_SIZE, classId } from "./runtime";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
export abstract class ArrayBufferView {
|
||||
|
||||
@unsafe data: ArrayBuffer;
|
||||
@unsafe dataStart: usize;
|
||||
@unsafe dataLength: u32;
|
||||
|
||||
protected constructor(length: i32, alignLog2: i32) {
|
||||
if (<u32>length > <u32>runtime.MAX_BYTELENGTH >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = new ArrayBuffer(length = length << alignLog2);
|
||||
this.data = buffer;
|
||||
this.dataStart = changetype<usize>(buffer);
|
||||
this.dataLength = length;
|
||||
}
|
||||
|
||||
get byteOffset(): i32 {
|
||||
return <i32>(this.dataStart - changetype<usize>(this.data));
|
||||
}
|
||||
|
||||
get byteLength(): i32 {
|
||||
return this.dataLength;
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
ERROR("missing implementation: subclasses must implement ArrayBufferView#length");
|
||||
return unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
@sealed export class ArrayBuffer {
|
||||
|
||||
static isView<T>(value: T): bool {
|
||||
@ -22,24 +50,24 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
}
|
||||
|
||||
constructor(length: i32) {
|
||||
if (<u32>length > <u32>MAX_BYTELENGTH) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = ALLOCATE(<usize>length);
|
||||
if (<u32>length > <u32>runtime.MAX_BYTELENGTH) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = runtime.allocate(<usize>length);
|
||||
memory.fill(changetype<usize>(buffer), 0, <usize>length);
|
||||
return REGISTER<ArrayBuffer>(buffer);
|
||||
return changetype<ArrayBuffer>(runtime.register(buffer, classId<ArrayBuffer>()));
|
||||
}
|
||||
|
||||
get byteLength(): i32 {
|
||||
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize;
|
||||
}
|
||||
|
||||
slice(begin: i32 = 0, end: i32 = MAX_BYTELENGTH): ArrayBuffer {
|
||||
slice(begin: i32 = 0, end: i32 = runtime.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);
|
||||
var outSize = <usize>max(end - begin, 0);
|
||||
var out = ALLOCATE(outSize);
|
||||
var out = runtime.allocate(outSize);
|
||||
memory.copy(out, changetype<usize>(this) + <usize>begin, outSize);
|
||||
return REGISTER<ArrayBuffer>(out);
|
||||
return changetype<ArrayBuffer>(runtime.register(out, classId<ArrayBuffer>()));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { MAX_BYTELENGTH } from "./runtime";
|
||||
import { runtime } from "./runtime";
|
||||
import { ArrayBuffer } from "./arraybuffer";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
@ -17,7 +17,7 @@ export class DataView {
|
||||
) {
|
||||
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; // FIXME
|
||||
if (
|
||||
i32(<u32>byteLength > <u32>MAX_BYTELENGTH) |
|
||||
i32(<u32>byteLength > <u32>runtime.MAX_BYTELENGTH) |
|
||||
i32(<u32>byteOffset + byteLength > <u32>buffer.byteLength)
|
||||
) throw new RangeError(E_INVALIDLENGTH);
|
||||
this.data = buffer; // links
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ALLOCATE, REGISTER, MAX_BYTELENGTH, HEADER, HEADER_SIZE, classId } from "./runtime";
|
||||
import { runtime, classId, HEADER, HEADER_SIZE } from "./runtime";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
|
||||
|
||||
// NOTE: DO NOT USE YET!
|
||||
@ -10,16 +10,16 @@ export class FixedArray<T> {
|
||||
[key: number]: T;
|
||||
|
||||
constructor(length: i32) {
|
||||
if (<u32>length > <u32>MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (<u32>length > <u32>runtime.MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (isReference<T>()) {
|
||||
if (!isNullable<T>()) {
|
||||
if (length) throw new Error(E_HOLEYARRAY);
|
||||
}
|
||||
}
|
||||
var outSize = <usize>length << alignof<T>();
|
||||
var out = ALLOCATE(outSize);
|
||||
var out = runtime.allocate(outSize);
|
||||
memory.fill(out, 0, outSize);
|
||||
return REGISTER<FixedArray<T>>(out);
|
||||
return changetype<FixedArray<T>>(runtime.register(out, classId<FixedArray<T>>()));
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
|
@ -20,7 +20,9 @@ export namespace gc {
|
||||
else throw new Error(E_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
/** Retains a reference, making sure that it doesn't become collected. */
|
||||
/** Retains a managed object externally, making sure that it doesn't become collected. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function retain(ref: usize): void {
|
||||
var root = GC_ROOT;
|
||||
if (!root.has(ref)) {
|
||||
@ -28,21 +30,20 @@ export namespace gc {
|
||||
if (implemented) {
|
||||
if (isDefined(__ref_link)) __ref_link(ref, changetype<usize>(root));
|
||||
else if (isDefined(__ref_retain)) __ref_retain(ref);
|
||||
else assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Releases a reference, allowing it to become collected. */
|
||||
/** Releases a managed object externally, allowing it to become collected. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function release(ref: usize): void {
|
||||
var root = GC_ROOT;
|
||||
if (root.has(ref)) {
|
||||
root.delete(ref);
|
||||
if (implemented) {
|
||||
if (isDefined(__ref_link)) {
|
||||
if (isDefined(__ref_unlink)) __ref_unlink(ref, changetype<usize>(root));
|
||||
} else if (isDefined(__ref_retain)) __ref_release(ref);
|
||||
else assert(false);
|
||||
if (isDefined(__ref_unlink)) __ref_unlink(ref, changetype<usize>(root));
|
||||
else if (isDefined(__ref_release)) __ref_release(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
// The runtime provides common functionality that links runtime interfaces for memory management
|
||||
// and garbage collection to the standard library, making sure it all plays well together. However,
|
||||
// most of the garbage collector interface must still be implemented explicitly in standard library
|
||||
// components, because common abstractions for both tracing and reference counting would result in
|
||||
// unnecessary overhead (e.g. tracing needs parent references while rc does not etc.).
|
||||
// and garbage collection to the standard library, making sure it all plays well together.
|
||||
|
||||
import { AL_MASK, MAX_SIZE_32 } from "./util/allocator";
|
||||
import { HEAP_BASE, memory } from "./memory";
|
||||
import { Array } from "./array";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
/**
|
||||
* The common runtime object header prepended to all managed objects. Has a size of 16 bytes in
|
||||
@ -48,208 +45,122 @@ export declare function classId<T>(): u32;
|
||||
@unsafe @builtin
|
||||
export declare function iterateRoots(fn: (ref: usize) => void): void;
|
||||
|
||||
/** Adjusts an allocation to actual block size. Primarily targets TLSF. */
|
||||
export function ADJUSTOBLOCK(payloadSize: usize): usize {
|
||||
// round up to power of 2, e.g. with HEADER_SIZE=8:
|
||||
// 0 -> 2^3 = 8
|
||||
// 1..8 -> 2^4 = 16
|
||||
// 9..24 -> 2^5 = 32
|
||||
// ...
|
||||
// MAX_LENGTH -> 2^30 = 0x40000000 (MAX_SIZE_32)
|
||||
return <usize>1 << <usize>(<u32>32 - clz<u32>(payloadSize + HEADER_SIZE - 1));
|
||||
}
|
||||
/** Runtime implementation. */
|
||||
export namespace runtime {
|
||||
|
||||
/**
|
||||
* Allocates a runtime object that might eventually make its way into GC'ed userland as a
|
||||
* managed object. Implicitly prepends the common runtime header to the allocation.
|
||||
*/
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @inline
|
||||
export function ALLOCATE(payloadSize: usize): usize {
|
||||
return allocate(payloadSize);
|
||||
}
|
||||
/** Maximum byte length of any buffer-like object. */
|
||||
// @ts-ignore
|
||||
@lazy
|
||||
export const MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
||||
|
||||
function allocate(payloadSize: usize): usize {
|
||||
var header = changetype<HEADER>(memory.allocate(ADJUSTOBLOCK(payloadSize)));
|
||||
header.classId = HEADER_MAGIC;
|
||||
header.payloadSize = payloadSize;
|
||||
if (isDefined(__ref_collect)) {
|
||||
header.reserved1 = 0;
|
||||
header.reserved2 = 0;
|
||||
/** Adjusts an allocation to actual block size. Primarily targets TLSF. */
|
||||
export function adjust(payloadSize: usize): usize {
|
||||
// round up to power of 2, e.g. with HEADER_SIZE=8:
|
||||
// 0 -> 2^3 = 8
|
||||
// 1..8 -> 2^4 = 16
|
||||
// 9..24 -> 2^5 = 32
|
||||
// ...
|
||||
// MAX_LENGTH -> 2^30 = 0x40000000 (MAX_SIZE_32)
|
||||
return <usize>1 << <usize>(<u32>32 - clz<u32>(payloadSize + HEADER_SIZE - 1));
|
||||
}
|
||||
return changetype<usize>(header) + HEADER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the size of a previously allocated, but not yet registered, runtime object, for
|
||||
* example when a pre-allocated buffer turned out to be too small or too large. This works by
|
||||
* aligning dynamic allocations to actual block size internally so in the best case REALLOCATE
|
||||
* only updates payload size while in the worst case moves the object to a larger block.
|
||||
*/
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @inline
|
||||
export function REALLOCATE(ref: usize, newPayloadSize: usize): usize {
|
||||
return reallocate(ref, newPayloadSize);
|
||||
}
|
||||
|
||||
function reallocate(ref: usize, newPayloadSize: usize): usize {
|
||||
// Background: When managed objects are allocated these aren't immediately registered with GC
|
||||
// but can be used as scratch objects while unregistered. This is useful in situations where
|
||||
// the object must be reallocated multiple times because its final size isn't known beforehand,
|
||||
// e.g. in Array#filter, with only the final object making it into GC'ed userland.
|
||||
var header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||
var payloadSize = header.payloadSize;
|
||||
if (payloadSize < newPayloadSize) {
|
||||
let newAdjustedSize = ADJUSTOBLOCK(newPayloadSize);
|
||||
if (select(ADJUSTOBLOCK(payloadSize), 0, ref > HEAP_BASE) < newAdjustedSize) {
|
||||
// move if the allocation isn't large enough or not a heap object
|
||||
let newHeader = changetype<HEADER>(memory.allocate(newAdjustedSize));
|
||||
newHeader.classId = header.classId;
|
||||
if (isDefined(__ref_collect)) {
|
||||
newHeader.reserved1 = 0;
|
||||
newHeader.reserved2 = 0;
|
||||
}
|
||||
let newRef = changetype<usize>(newHeader) + HEADER_SIZE;
|
||||
memory.copy(newRef, ref, payloadSize);
|
||||
memory.fill(newRef + payloadSize, 0, newPayloadSize - payloadSize);
|
||||
if (header.classId == HEADER_MAGIC) {
|
||||
// free right away if not registered yet
|
||||
assert(ref > HEAP_BASE); // static objects aren't scratch objects
|
||||
memory.free(changetype<usize>(header));
|
||||
} else if (isDefined(__ref_collect)) {
|
||||
// if previously registered, register again
|
||||
// @ts-ignore: stub
|
||||
__ref_register(ref);
|
||||
}
|
||||
header = newHeader;
|
||||
ref = newRef;
|
||||
} else {
|
||||
// otherwise just clear additional memory within this block
|
||||
memory.fill(ref + payloadSize, 0, newPayloadSize - payloadSize);
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function allocate(payloadSize: usize): usize {
|
||||
var header = changetype<HEADER>(memory.allocate(adjust(payloadSize)));
|
||||
header.classId = HEADER_MAGIC;
|
||||
header.payloadSize = payloadSize;
|
||||
if (isDefined(__ref_collect)) {
|
||||
header.reserved1 = 0;
|
||||
header.reserved2 = 0;
|
||||
}
|
||||
} else {
|
||||
// if the size is the same or less, just update the header accordingly.
|
||||
// unused space is cleared when grown, so no need to do this here.
|
||||
return changetype<usize>(header) + HEADER_SIZE;
|
||||
}
|
||||
header.payloadSize = newPayloadSize;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a runtime object of kind T. Sets the internal class id within the runtime header
|
||||
* and asserts that the object hasn't been registered yet. If a tracing garbage collector is
|
||||
* present that requires initial insertion, the macro usually forwards a call to it. Once a
|
||||
* runtime object has been registed (makes it into userland), it cannot be DISCARD'ed anymore.
|
||||
*/
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @inline
|
||||
export function REGISTER<T>(ref: usize): T {
|
||||
if (!isReference<T>()) ERROR("reference expected");
|
||||
return changetype<T>(register(ref, classId<T>()));
|
||||
}
|
||||
|
||||
function register(ref: usize, classId: u32): usize {
|
||||
if (!ASC_NO_ASSERT) {
|
||||
assert(ref > HEAP_BASE); // must be a heap object
|
||||
let header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||
assert(header.classId == HEADER_MAGIC);
|
||||
header.classId = classId;
|
||||
} else {
|
||||
changetype<HEADER>(ref - HEADER_SIZE).classId = classId;
|
||||
}
|
||||
// @ts-ignore: stub
|
||||
if (isDefined(__ref_register)) __ref_register(ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards a runtime object that has not been registed and turned out to be unnecessary.
|
||||
* Essentially undoes the forgoing ALLOCATE. Should be avoided where possible.
|
||||
*/
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @inline
|
||||
export function DISCARD(ref: usize): void {
|
||||
discard(ref);
|
||||
}
|
||||
|
||||
function discard(ref: usize): void {
|
||||
if (!ASC_NO_ASSERT) {
|
||||
assert(ref > HEAP_BASE); // must be a heap object
|
||||
let header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||
assert(header.classId == HEADER_MAGIC);
|
||||
memory.free(changetype<usize>(header));
|
||||
} else {
|
||||
memory.free(changetype<usize>(ref - HEADER_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a new array and optionally initializes is with existing data from source. Used by the
|
||||
* compiler to either wrap static array data in a new instance or pre-initialize the memory used
|
||||
* by an array literal. Does not zero the backing buffer!
|
||||
*/
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @inline
|
||||
export function MAKEARRAY<V>(capacity: i32, source: usize = 0): Array<V> {
|
||||
return changetype<Array<V>>(makeArray(capacity, classId<V[]>(), alignof<V>(), source));
|
||||
}
|
||||
|
||||
function makeArray(capacity: i32, cid: u32, alignLog2: usize, source: usize): usize {
|
||||
var array = register(allocate(offsetof<i32[]>()), cid);
|
||||
var bufferSize = <usize>capacity << alignLog2;
|
||||
var buffer = register(allocate(<usize>capacity << alignLog2), classId<ArrayBuffer>());
|
||||
changetype<ArrayBufferView>(array).data = changetype<ArrayBuffer>(buffer); // links
|
||||
changetype<ArrayBufferView>(array).dataStart = buffer;
|
||||
changetype<ArrayBufferView>(array).dataLength = bufferSize;
|
||||
store<i32>(changetype<usize>(array), capacity, offsetof<i32[]>("length_"));
|
||||
if (source) memory.copy(buffer, source, bufferSize);
|
||||
return array;
|
||||
}
|
||||
|
||||
import { ArrayBuffer } from "./arraybuffer";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
/** Maximum byte length of any buffer. */
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
export const MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
||||
|
||||
/** Hard wired ArrayBufferView interface. */
|
||||
export abstract class ArrayBufferView {
|
||||
|
||||
/** Backing buffer. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
data: ArrayBuffer;
|
||||
export function reallocate(ref: usize, newPayloadSize: usize): usize {
|
||||
// Background: When managed objects are allocated these aren't immediately registered with GC
|
||||
// but can be used as scratch objects while unregistered. This is useful in situations where
|
||||
// the object must be reallocated multiple times because its final size isn't known beforehand,
|
||||
// e.g. in Array#filter, with only the final object making it into GC'ed userland.
|
||||
var header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||
var payloadSize = header.payloadSize;
|
||||
if (payloadSize < newPayloadSize) {
|
||||
let newAdjustedSize = adjust(newPayloadSize);
|
||||
if (select(adjust(payloadSize), 0, ref > HEAP_BASE) < newAdjustedSize) {
|
||||
// move if the allocation isn't large enough or not a heap object
|
||||
let newHeader = changetype<HEADER>(memory.allocate(newAdjustedSize));
|
||||
newHeader.classId = header.classId;
|
||||
if (isDefined(__ref_collect)) {
|
||||
newHeader.reserved1 = 0;
|
||||
newHeader.reserved2 = 0;
|
||||
}
|
||||
let newRef = changetype<usize>(newHeader) + HEADER_SIZE;
|
||||
memory.copy(newRef, ref, payloadSize);
|
||||
memory.fill(newRef + payloadSize, 0, newPayloadSize - payloadSize);
|
||||
if (header.classId == HEADER_MAGIC) {
|
||||
// free right away if not registered yet
|
||||
assert(ref > HEAP_BASE); // static objects aren't scratch objects
|
||||
memory.free(changetype<usize>(header));
|
||||
} else if (isDefined(__ref_collect)) {
|
||||
// if previously registered, register again
|
||||
// @ts-ignore: stub
|
||||
__ref_register(ref);
|
||||
}
|
||||
header = newHeader;
|
||||
ref = newRef;
|
||||
} else {
|
||||
// otherwise just clear additional memory within this block
|
||||
memory.fill(ref + payloadSize, 0, newPayloadSize - payloadSize);
|
||||
}
|
||||
} else {
|
||||
// if the size is the same or less, just update the header accordingly.
|
||||
// unused space is cleared when grown, so no need to do this here.
|
||||
}
|
||||
header.payloadSize = newPayloadSize;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/** Data start offset in memory. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
dataStart: usize;
|
||||
export function discard(ref: usize): void {
|
||||
if (!ASC_NO_ASSERT) {
|
||||
assert(ref > HEAP_BASE); // must be a heap object
|
||||
let header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||
assert(header.classId == HEADER_MAGIC);
|
||||
memory.free(changetype<usize>(header));
|
||||
} else {
|
||||
memory.free(changetype<usize>(ref - HEADER_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
/** Data length in memory, counted from `dataStart`. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
dataLength: u32;
|
||||
|
||||
protected constructor(length: i32, alignLog2: i32) {
|
||||
if (<u32>length > <u32>MAX_BYTELENGTH >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = new ArrayBuffer(length = length << alignLog2);
|
||||
this.data = buffer;
|
||||
this.dataStart = changetype<usize>(buffer);
|
||||
this.dataLength = length;
|
||||
export function register(ref: usize, classId: u32): usize {
|
||||
if (!ASC_NO_ASSERT) {
|
||||
assert(ref > HEAP_BASE); // must be a heap object
|
||||
let header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||
assert(header.classId == HEADER_MAGIC);
|
||||
header.classId = classId;
|
||||
} else {
|
||||
changetype<HEADER>(ref - HEADER_SIZE).classId = classId;
|
||||
}
|
||||
if (isDefined(__ref_register)) __ref_register(ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
get byteOffset(): i32 {
|
||||
return <i32>(this.dataStart - changetype<usize>(this.data));
|
||||
}
|
||||
|
||||
get byteLength(): i32 {
|
||||
return this.dataLength;
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
ERROR("missing implementation: subclasses must implement ArrayBufferView#length");
|
||||
return unreachable();
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function makeArray(capacity: i32, cid: u32, alignLog2: usize, source: usize = 0): usize {
|
||||
var array = runtime.register(runtime.allocate(offsetof<i32[]>()), cid);
|
||||
var bufferSize = <usize>capacity << alignLog2;
|
||||
var buffer = runtime.register(runtime.allocate(<usize>capacity << alignLog2), classId<ArrayBuffer>());
|
||||
changetype<ArrayBufferView>(array).data = changetype<ArrayBuffer>(buffer); // links
|
||||
changetype<ArrayBufferView>(array).dataStart = buffer;
|
||||
changetype<ArrayBufferView>(array).dataLength = bufferSize;
|
||||
store<i32>(changetype<usize>(array), capacity, offsetof<i32[]>("length_"));
|
||||
if (source) memory.copy(buffer, source, bufferSize);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { ALLOCATE, REGISTER, HEADER, HEADER_SIZE, MAKEARRAY, ArrayBufferView } from "./runtime";
|
||||
import { MAX_SIZE_32 } from "./util/allocator";
|
||||
import { runtime, HEADER, HEADER_SIZE, classId } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
@ -15,15 +16,15 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
// TODO Add and handle second argument
|
||||
static fromCharCode(code: i32): String {
|
||||
var out = ALLOCATE(2);
|
||||
var out = runtime.allocate(2);
|
||||
store<u16>(out, <u16>code);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
static fromCodePoint(code: i32): String {
|
||||
assert(<u32>code <= 0x10FFFF);
|
||||
var sur = code > 0xFFFF;
|
||||
var out = ALLOCATE((i32(sur) + 1) << 1);
|
||||
var out = runtime.allocate((i32(sur) + 1) << 1);
|
||||
if (!sur) {
|
||||
store<u16>(out, <u16>code);
|
||||
} else {
|
||||
@ -32,15 +33,15 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
let lo: u32 = (code & 0x3FF) + 0xDC00;
|
||||
store<u32>(out, (hi << 16) | lo);
|
||||
}
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
@operator("[]") charAt(pos: i32): String {
|
||||
assert(this !== null);
|
||||
if (<u32>pos >= <u32>this.length) return changetype<String>("");
|
||||
var out = ALLOCATE(2);
|
||||
var out = runtime.allocate(2);
|
||||
store<u16>(out, load<u16>(changetype<usize>(this) + (<usize>pos << 1)));
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
charCodeAt(pos: i32): i32 {
|
||||
@ -57,8 +58,8 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
|
||||
}
|
||||
|
||||
@operator("+") private static __concat(left: string, right: string): string {
|
||||
return select<string>(left, "null", left !== null).concat(right);
|
||||
@operator("+") private static __concat(left: String, right: String): String {
|
||||
return select<String>(left, changetype<String>("null"), left !== null).concat(right);
|
||||
}
|
||||
|
||||
concat(other: String): String {
|
||||
@ -67,10 +68,10 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
var otherSize: isize = other.length << 1;
|
||||
var outSize: usize = thisSize + otherSize;
|
||||
if (outSize == 0) return changetype<String>("");
|
||||
var out = ALLOCATE(outSize);
|
||||
var out = runtime.allocate(outSize);
|
||||
memory.copy(out, changetype<usize>(this), thisSize);
|
||||
memory.copy(out + thisSize, changetype<usize>(other), otherSize);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
endsWith(searchString: String, endPosition: i32 = String.MAX_LENGTH): bool {
|
||||
@ -180,9 +181,9 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (intStart < 0) intStart = max(size + intStart, 0);
|
||||
var resultLength = min(max(end, 0), size - intStart);
|
||||
if (resultLength <= 0) return changetype<String>("");
|
||||
var out = ALLOCATE(resultLength << 1);
|
||||
var out = runtime.allocate(resultLength << 1);
|
||||
memory.copy(out, changetype<usize>(this) + intStart, resultLength);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
||||
@ -195,9 +196,9 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
len = toPos - fromPos;
|
||||
if (!len) return changetype<String>("");
|
||||
if (!fromPos && toPos == this.length << 1) return this;
|
||||
var out = ALLOCATE(len);
|
||||
var out = runtime.allocate(len);
|
||||
memory.copy(out, changetype<usize>(this) + fromPos, len);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
trim(): String {
|
||||
@ -223,9 +224,9 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
}
|
||||
if (!size) return changetype<String>("");
|
||||
if (!start && size == length << 1) return this;
|
||||
var out = ALLOCATE(size);
|
||||
var out = runtime.allocate(size);
|
||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
@inline
|
||||
@ -253,9 +254,9 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (!offset) return this;
|
||||
size -= offset;
|
||||
if (!size) return changetype<String>("");
|
||||
var out = ALLOCATE(size);
|
||||
var out = runtime.allocate(size);
|
||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
trimEnd(): String {
|
||||
@ -272,9 +273,9 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
}
|
||||
if (!size) return changetype<String>("");
|
||||
if (size == originalSize) return this;
|
||||
var out = ALLOCATE(size);
|
||||
var out = runtime.allocate(size);
|
||||
memory.copy(out, changetype<usize>(this), size);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
padStart(targetLength: i32, padString: string = " "): String {
|
||||
@ -284,7 +285,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
var padSize = <usize>padString.length << 1;
|
||||
if (targetSize < thisSize || !padSize) return this;
|
||||
var prependSize = targetSize - thisSize;
|
||||
var out = ALLOCATE(targetSize);
|
||||
var out = runtime.allocate(targetSize);
|
||||
if (prependSize > padSize) {
|
||||
let repeatCount = (prependSize - 2) / padSize;
|
||||
let restBase = repeatCount * padSize;
|
||||
@ -295,7 +296,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
memory.copy(out, changetype<usize>(padString), prependSize);
|
||||
}
|
||||
memory.copy(out + prependSize, changetype<usize>(this), thisSize);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
padEnd(targetLength: i32, padString: string = " "): String {
|
||||
@ -305,7 +306,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
var padSize = <usize>padString.length << 1;
|
||||
if (targetSize < thisSize || !padSize) return this;
|
||||
var appendSize = targetSize - thisSize;
|
||||
var out = ALLOCATE(targetSize);
|
||||
var out = runtime.allocate(targetSize);
|
||||
memory.copy(out, changetype<usize>(this), thisSize);
|
||||
if (appendSize > padSize) {
|
||||
let repeatCount = (appendSize - 2) / padSize;
|
||||
@ -316,7 +317,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
} else {
|
||||
memory.copy(out + thisSize, changetype<usize>(padString), appendSize);
|
||||
}
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
repeat(count: i32 = 0): String {
|
||||
@ -330,9 +331,9 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
if (count == 0 || !length) return changetype<String>("");
|
||||
if (count == 1) return this;
|
||||
var out = ALLOCATE((length * count) << 1);
|
||||
var out = runtime.allocate((length * count) << 1);
|
||||
memory.repeat(out, changetype<usize>(this), <usize>length << 1, count);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
slice(beginIndex: i32, endIndex: i32 = i32.MAX_VALUE): String {
|
||||
@ -341,48 +342,48 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
var end = endIndex < 0 ? max(endIndex + len, 0) : min(endIndex, len);
|
||||
len = end - begin;
|
||||
if (len <= 0) return changetype<String>("");
|
||||
var out = ALLOCATE(len << 1);
|
||||
var out = runtime.allocate(len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>begin << 1), <usize>len << 1);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
split(separator: String | null = null, limit: i32 = i32.MAX_VALUE): String[] {
|
||||
assert(this !== null);
|
||||
if (!limit) return MAKEARRAY<String>(0);
|
||||
if (!limit) return changetype<String[]>(runtime.makeArray(0, classId<String[]>(), alignof<String>()));
|
||||
if (separator === null) return <String[]>[this];
|
||||
var length: isize = this.length;
|
||||
var sepLen: isize = separator.length;
|
||||
if (limit < 0) limit = i32.MAX_VALUE;
|
||||
if (!sepLen) {
|
||||
if (!length) return MAKEARRAY<String>(0);
|
||||
if (!length) return changetype<String[]>(runtime.makeArray(0, classId<String>(), alignof<String>()));
|
||||
// split by chars
|
||||
length = min<isize>(length, <isize>limit);
|
||||
let result = MAKEARRAY<String>(length);
|
||||
let result = changetype<String[]>(runtime.makeArray(length, classId<String[]>(), alignof<String>()));
|
||||
let resultStart = changetype<ArrayBufferView>(result).dataStart;
|
||||
for (let i: isize = 0; i < length; ++i) {
|
||||
let charStr = REGISTER<String>(ALLOCATE(2));
|
||||
store<u16>(changetype<usize>(charStr), load<u16>(changetype<usize>(this) + (<usize>i << 1)));
|
||||
store<String>(resultStart + (<usize>i << alignof<usize>()), charStr); // result[i] = charStr
|
||||
let charStr = runtime.allocate(2);
|
||||
store<u16>(charStr, load<u16>(changetype<usize>(this) + (<usize>i << 1)));
|
||||
store<usize>(resultStart + (<usize>i << alignof<usize>()), charStr); // result[i] = charStr
|
||||
runtime.register(charStr, classId<String>());
|
||||
if (isManaged<String>()) {
|
||||
if (isDefined(__ref_link)) __ref_link(changetype<usize>(charStr), changetype<usize>(result));
|
||||
else if (isDefined(__ref_retain)) __ref_retain(changetype<usize>(charStr));
|
||||
else assert(false);
|
||||
if (isDefined(__ref_retain)) __ref_retain(changetype<usize>(charStr));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else if (!length) {
|
||||
let result = MAKEARRAY<String>(1);
|
||||
let result = changetype<String[]>(runtime.makeArray(1, classId<String[]>(), alignof<String>()));
|
||||
store<string>(changetype<ArrayBufferView>(result).dataStart, ""); // no need to register/link
|
||||
return result;
|
||||
}
|
||||
var result = MAKEARRAY<String>(0);
|
||||
var result = changetype<String[]>(runtime.makeArray(0, classId<String[]>(), alignof<String>()));
|
||||
var end = 0, start = 0, i = 0;
|
||||
while ((end = this.indexOf(separator!, start)) != -1) {
|
||||
let len = end - start;
|
||||
if (len > 0) {
|
||||
let out = ALLOCATE(<usize>len << 1);
|
||||
let out = runtime.allocate(<usize>len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||
result.push(REGISTER<String>(out));
|
||||
result.push(changetype<String>(runtime.register(out, classId<String>())));
|
||||
} else {
|
||||
result.push(changetype<String>(""));
|
||||
}
|
||||
@ -390,15 +391,15 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
start = end + sepLen;
|
||||
}
|
||||
if (!start) {
|
||||
let result = MAKEARRAY<String>(1);
|
||||
let result = changetype<String[]>(runtime.makeArray(1, classId<String[]>(), alignof<String>()));
|
||||
unchecked(result[0] = this);
|
||||
return result;
|
||||
}
|
||||
var len = length - start;
|
||||
if (len > 0) {
|
||||
let out = ALLOCATE(<usize>len << 1);
|
||||
let out = runtime.allocate(<usize>len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||
result.push(REGISTER<String>(out));
|
||||
result.push(changetype<String>(runtime.register(out, classId<String>())));
|
||||
} else {
|
||||
result.push(changetype<String>(""));
|
||||
}
|
||||
@ -433,8 +434,8 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
return len;
|
||||
}
|
||||
|
||||
static fromUTF8(ptr: usize, len: usize): string {
|
||||
if (len < 1) return changetype<string>("");
|
||||
static fromUTF8(ptr: usize, len: usize): String {
|
||||
if (len < 1) return changetype<String>("");
|
||||
var ptrPos = <usize>0;
|
||||
var buf = memory.allocate(<usize>len << 1);
|
||||
var bufPos = <usize>0;
|
||||
@ -470,10 +471,10 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
}
|
||||
}
|
||||
assert(ptrPos == len);
|
||||
var out = ALLOCATE(bufPos);
|
||||
var out = runtime.allocate(bufPos);
|
||||
memory.copy(changetype<usize>(out), buf, bufPos);
|
||||
memory.free(buf);
|
||||
return REGISTER<string>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
toUTF8(): usize {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ALLOCATE, REGISTER, ArrayBufferView } from "./runtime";
|
||||
import { runtime, classId } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort";
|
||||
import { E_INDEXOUTOFRANGE } from "./util/error";
|
||||
|
||||
@ -960,13 +961,13 @@ function SUBARRAY<TArray extends ArrayBufferView, T>(
|
||||
else begin = min(begin, length);
|
||||
if (end < 0) end = max(length + end, begin);
|
||||
else end = max(min(end, length), begin);
|
||||
var out = REGISTER<TArray>(ALLOCATE(offsetof<TArray>()));
|
||||
var out = runtime.allocate(offsetof<TArray>());
|
||||
var data = array.data;
|
||||
var dataStart = array.dataStart;
|
||||
changetype<ArrayBufferView>(out).data = data; // links
|
||||
changetype<ArrayBufferView>(out).dataStart = dataStart + (<usize>begin << alignof<T>());
|
||||
changetype<ArrayBufferView>(out).dataLength = (end - begin) << alignof<T>();
|
||||
return out;
|
||||
return changetype<TArray>(runtime.register(out, classId<TArray>()));
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ALLOCATE, REGISTER, DISCARD, ArrayBufferView } from "../runtime";
|
||||
import { runtime, classId } from "../runtime";
|
||||
import { ArrayBufferView } from "../arraybuffer";
|
||||
import { CharCode } from "./string";
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@ -262,10 +263,10 @@ export function utoa32(value: u32): String {
|
||||
if (!value) return "0";
|
||||
|
||||
var decimals = decimalCount32(value);
|
||||
var out = ALLOCATE(decimals << 1);
|
||||
var out = runtime.allocate(decimals << 1);
|
||||
|
||||
utoa32_core(changetype<usize>(out), value, decimals);
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
export function itoa32(value: i32): String {
|
||||
@ -275,12 +276,12 @@ export function itoa32(value: i32): String {
|
||||
if (sign) value = -value;
|
||||
|
||||
var decimals = decimalCount32(value) + u32(sign);
|
||||
var out = ALLOCATE(decimals << 1);
|
||||
var out = runtime.allocate(decimals << 1);
|
||||
|
||||
utoa32_core(changetype<usize>(out), value, decimals);
|
||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
export function utoa64(value: u64): String {
|
||||
@ -290,14 +291,14 @@ export function utoa64(value: u64): String {
|
||||
if (value <= u32.MAX_VALUE) {
|
||||
let val32 = <u32>value;
|
||||
let decimals = decimalCount32(val32);
|
||||
out = ALLOCATE(decimals << 1);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
utoa32_core(out, val32, decimals);
|
||||
} else {
|
||||
let decimals = decimalCount64(value);
|
||||
out = ALLOCATE(decimals << 1);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
utoa64_core(changetype<usize>(out), value, decimals);
|
||||
}
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
export function itoa64(value: i64): String {
|
||||
@ -310,16 +311,16 @@ export function itoa64(value: i64): String {
|
||||
if (<u64>value <= <u64>u32.MAX_VALUE) {
|
||||
let val32 = <u32>value;
|
||||
let decimals = decimalCount32(val32) + u32(sign);
|
||||
out = ALLOCATE(decimals << 1);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
utoa32_core(changetype<usize>(out), val32, decimals);
|
||||
} else {
|
||||
let decimals = decimalCount64(value) + u32(sign);
|
||||
out = ALLOCATE(decimals << 1);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
utoa64_core(changetype<usize>(out), value, decimals);
|
||||
}
|
||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||
|
||||
return REGISTER<String>(out);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
}
|
||||
|
||||
export function itoa<T extends number>(value: T): String {
|
||||
@ -624,10 +625,10 @@ export function dtoa(value: f64): String {
|
||||
if (isNaN<f64>(value)) return "NaN";
|
||||
return select<String>("-Infinity", "Infinity", value < 0);
|
||||
}
|
||||
var temp = ALLOCATE(MAX_DOUBLE_LENGTH << 1);
|
||||
var temp = runtime.allocate(MAX_DOUBLE_LENGTH << 1);
|
||||
var length = dtoa_core(temp, value);
|
||||
var result = changetype<String>(temp).substring(0, length);
|
||||
DISCARD(temp);
|
||||
var result = changetype<String>(temp).substring(0, length); // registers
|
||||
runtime.discard(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user