mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-22 11:11:43 +00:00
implement __runtime_flags
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { MAX_BYTELENGTH, reallocate } from "./util/runtime";
|
||||
import { MAX_BYTELENGTH, allocate, reallocate, discard, register } from "./util/runtime";
|
||||
import { COMPARATOR, SORT } from "./util/sort";
|
||||
import { runtime, __runtime_id, __gc_mark_members } from "./runtime";
|
||||
import { ArrayBuffer, ArrayBufferView } from "./arraybuffer";
|
||||
@ -126,7 +126,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
if (isDefined(__ref_link)) {
|
||||
if (isDefined(__ref_unlink)) if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||
if (value !== null) __ref_link(changetype<usize>(value), changetype<usize>(this));
|
||||
} else if (__ref_retain) {
|
||||
} else if (isDefined(__ref_retain)) {
|
||||
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
||||
if (value !== null) __ref_retain(changetype<usize>(value));
|
||||
} else assert(false);
|
||||
@ -561,7 +561,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 = runtime.allocate(estLen << 1);
|
||||
var result = allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: bool;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -593,10 +593,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
runtime.discard(result);
|
||||
discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
return changetype<string>(register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_int(separator: string = ","): string {
|
||||
@ -609,7 +609,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 = runtime.allocate(estLen << 1);
|
||||
var result = allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -630,10 +630,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);
|
||||
runtime.discard(result);
|
||||
discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
return changetype<string>(register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_flt(separator: string = ","): string {
|
||||
@ -650,7 +650,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
const valueLen = MAX_DOUBLE_LENGTH;
|
||||
var sepLen = separator.length;
|
||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||
var result = runtime.allocate(estLen << 1);
|
||||
var result = allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -675,10 +675,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
);
|
||||
if (estLen > offset) {
|
||||
let trimmed = changetype<string>(result).substring(0, offset);
|
||||
runtime.discard(result);
|
||||
discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
return changetype<string>(register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_str(separator: string = ","): string {
|
||||
@ -695,7 +695,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
if (value !== null) estLen += value.length;
|
||||
}
|
||||
var offset = 0;
|
||||
var result = runtime.allocate((estLen + sepLen * lastIndex) << 1);
|
||||
var result = allocate((estLen + sepLen * lastIndex) << 1);
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
||||
if (value !== null) {
|
||||
@ -724,7 +724,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
<usize>changetype<string>(value).length << 1
|
||||
);
|
||||
}
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
return changetype<string>(register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_arr(separator: string = ","): string {
|
||||
@ -761,7 +761,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 = runtime.allocate(estLen << 1);
|
||||
var result = allocate(estLen << 1);
|
||||
var offset = 0;
|
||||
var value: T;
|
||||
for (let i = 0; i < lastIndex; ++i) {
|
||||
@ -793,10 +793,10 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
if (estLen > offset) {
|
||||
let out = changetype<string>(result).substring(0, offset);
|
||||
runtime.discard(result);
|
||||
discard(result);
|
||||
return out; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
return changetype<string>(register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./util/runtime";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { HEADER, HEADER_SIZE, MAX_BYTELENGTH, allocate, register } from "./util/runtime";
|
||||
import { __runtime_id } from "./runtime";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
export abstract class ArrayBufferView {
|
||||
@ -52,9 +52,9 @@ export abstract class ArrayBufferView {
|
||||
|
||||
constructor(length: i32) {
|
||||
if (<u32>length > <u32>MAX_BYTELENGTH) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = runtime.allocate(<usize>length);
|
||||
var buffer = allocate(<usize>length);
|
||||
memory.fill(changetype<usize>(buffer), 0, <usize>length);
|
||||
return changetype<ArrayBuffer>(runtime.register(buffer, __runtime_id<ArrayBuffer>()));
|
||||
return changetype<ArrayBuffer>(register(buffer, __runtime_id<ArrayBuffer>()));
|
||||
}
|
||||
|
||||
get byteLength(): i32 {
|
||||
@ -66,9 +66,9 @@ export abstract class ArrayBufferView {
|
||||
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 = runtime.allocate(outSize);
|
||||
var out = allocate(outSize);
|
||||
memory.copy(out, changetype<usize>(this) + <usize>begin, outSize);
|
||||
return changetype<ArrayBuffer>(runtime.register(out, __runtime_id<ArrayBuffer>()));
|
||||
return changetype<ArrayBuffer>(register(out, __runtime_id<ArrayBuffer>()));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
@ -3,7 +3,7 @@
|
||||
// After the paper by D. Bacon et al., 2001, IBM T.J. Watson Research Center
|
||||
// https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon03Pure.pdf
|
||||
|
||||
import { HEADER, HEADER_SIZE } from "../runtime";
|
||||
import { HEADER_SIZE } from "../util/runtime";
|
||||
|
||||
ERROR("not implemented");
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./util/runtime";
|
||||
import { runtime, __runtime_id, __gc_mark_members } from "./runtime";
|
||||
import { HEADER, HEADER_SIZE, MAX_BYTELENGTH, allocate, register } from "./util/runtime";
|
||||
import { __runtime_id, __gc_mark_members } from "./runtime";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
|
||||
|
||||
// NOTE: DO NOT USE YET!
|
||||
@ -18,9 +18,9 @@ export class FixedArray<T> {
|
||||
}
|
||||
}
|
||||
var outSize = <usize>length << alignof<T>();
|
||||
var out = runtime.allocate(outSize);
|
||||
var out = allocate(outSize);
|
||||
memory.fill(out, 0, outSize);
|
||||
return changetype<FixedArray<T>>(runtime.register(out, __runtime_id<FixedArray<T>>()));
|
||||
return changetype<FixedArray<T>>(register(out, __runtime_id<FixedArray<T>>()));
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
|
@ -295,7 +295,7 @@ export class Map<K,V> {
|
||||
if (isNullable<V>()) {
|
||||
if (val) {
|
||||
__ref_mark(val);
|
||||
__gc_mark_members(__runtime_id<V>(), val);
|
||||
__gc_mark_members(__runtime_id<V>(), val);
|
||||
}
|
||||
} else {
|
||||
__ref_mark(val);
|
||||
|
@ -1,21 +1,65 @@
|
||||
// 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.
|
||||
|
||||
import { HEADER, HEADER_SIZE, HEADER_MAGIC, adjust } from "./util/runtime";
|
||||
import { HEAP_BASE, memory } from "./memory";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { HEADER, HEADER_SIZE, allocate, register } from "./util/runtime";
|
||||
import { E_NOTIMPLEMENTED } from "./util/error";
|
||||
import { memory } from "./memory";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
/** Gets the computed unique id of a class type. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
@builtin
|
||||
export declare function __runtime_id<T>(): u32;
|
||||
|
||||
/** Tests if a managed class is the same as or a superclass of another. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
@builtin
|
||||
export declare function __runtime_instanceof(id: u32, superId: u32): bool;
|
||||
|
||||
/** Runtime flags. */
|
||||
const enum RuntimeFlags { // keep in sync with src/program.ts
|
||||
NONE = 0,
|
||||
/** Type is an `Array`. */
|
||||
ARRAY = 1 << 0,
|
||||
/** Type is a `Set`. */
|
||||
SET = 1 << 1,
|
||||
/** Type is a `Map`. */
|
||||
MAP = 1 << 2,
|
||||
/** Value alignment of 1 byte. */
|
||||
VALUE_ALIGN_0 = 1 << 3,
|
||||
/** Value alignment of 2 bytes. */
|
||||
VALUE_ALIGN_1 = 1 << 4,
|
||||
/** Value alignment of 4 bytes. */
|
||||
VALUE_ALIGN_2 = 1 << 5,
|
||||
/** Value alignment of 8 bytes. */
|
||||
VALUE_ALIGN_3 = 1 << 6,
|
||||
/** Value alignment of 16 bytes. */
|
||||
VALUE_ALIGN_4 = 1 << 7,
|
||||
/** Value type is nullable. */
|
||||
VALUE_NULLABLE = 1 << 8,
|
||||
/** Value type is managed. */
|
||||
VALUE_MANAGED = 1 << 9,
|
||||
/** Key alignment of 1 byte. */
|
||||
KEY_ALIGN_0 = 1 << 10,
|
||||
/** Key alignment of 2 bytes. */
|
||||
KEY_ALIGN_1 = 1 << 11,
|
||||
/** Key alignment of 4 bytes. */
|
||||
KEY_ALIGN_2 = 1 << 12,
|
||||
/** Key alignment of 8 bytes. */
|
||||
KEY_ALIGN_3 = 1 << 13,
|
||||
/** Key alignment of 16 bytes. */
|
||||
KEY_ALIGN_4 = 1 << 14,
|
||||
/** Key type is nullable. */
|
||||
KEY_NULLABLE = 1 << 15,
|
||||
/** Key type is managed. */
|
||||
KEY_MANAGED = 1 << 16
|
||||
}
|
||||
|
||||
/** Gets the runtime flags of the managed type represented by the specified runtime id. */
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function __runtime_flags(id: u32): RuntimeFlags;
|
||||
|
||||
/** Marks root objects when a tracing GC is present. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
@ -42,66 +86,31 @@ export class runtime {
|
||||
: false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Runtime implementation. */
|
||||
export namespace runtime {
|
||||
|
||||
/** Allocates the memory necessary to represent a managed object of the specified size. */
|
||||
// @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;
|
||||
}
|
||||
return changetype<usize>(header) + HEADER_SIZE;
|
||||
export function flags(id: u32): RuntimeFlags {
|
||||
return __runtime_flags(id);
|
||||
}
|
||||
|
||||
/** Discards the memory of a managed object that hasn't been registered yet. */
|
||||
/** Allocates and registers, but doesn't initialize the data of, a new managed object of the specified kind. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/** Registers a managed object of the kind represented by the specified runtime id. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function register(ref: usize, id: 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 = id;
|
||||
} else {
|
||||
changetype<HEADER>(ref - HEADER_SIZE).classId = id;
|
||||
}
|
||||
if (isDefined(__ref_register)) __ref_register(ref);
|
||||
return ref;
|
||||
export function newObject(payloadSize: u32, id: u32): usize {
|
||||
return register(allocate(<usize>payloadSize), id);
|
||||
}
|
||||
|
||||
/** Allocates and registers, but doesn't initialize the data of, a new `String` of the specified length. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function newString(length: i32): usize {
|
||||
return register(allocate(<usize>length << 1), __runtime_id<String>());
|
||||
return newObject(length << 1, __runtime_id<String>());
|
||||
}
|
||||
|
||||
/** Allocates and registers, but doesn't initialize the data of, a new `ArrayBuffer` of the specified byteLength. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function newArrayBuffer(byteLength: i32): usize {
|
||||
return register(allocate(<usize>byteLength), __runtime_id<ArrayBuffer>());
|
||||
return newObject(byteLength, __runtime_id<ArrayBuffer>());
|
||||
}
|
||||
|
||||
/** Allocates and registers, but doesn't initialize the data of, a new `Array` of the specified length and element alignment.*/
|
||||
@ -121,9 +130,40 @@ export namespace runtime {
|
||||
changetype<ArrayBufferView>(array).dataLength = bufferSize;
|
||||
store<i32>(changetype<usize>(array), length, offsetof<i32[]>("length_"));
|
||||
if (data) memory.copy(buffer, data, bufferSize);
|
||||
// TODO: a way to determine whether the array has managed elements that must be linked?
|
||||
return array;
|
||||
}
|
||||
|
||||
// export function newArray2(id: u32, buffer: usize): usize {
|
||||
// var flags = __runtime_flags(id); // traps if invalid
|
||||
// var alignLog2 = (flags / RuntimeFlags.VALUE_ALIGN_0) & 31;
|
||||
// var byteLength: i32;
|
||||
// if (!buffer) {
|
||||
// buffer = newArrayBuffer(byteLength = 0);
|
||||
// } else {
|
||||
// byteLength = changetype<ArrayBuffer>(buffer).byteLength;
|
||||
// }
|
||||
// var array = register(allocate(offsetof<i32[]>()), id);
|
||||
// changetype<ArrayBufferView>(array).data = changetype<ArrayBuffer>(buffer); // links
|
||||
// changetype<ArrayBufferView>(array).dataStart = buffer;
|
||||
// changetype<ArrayBufferView>(array).dataLength = byteLength;
|
||||
// store<i32>(changetype<usize>(array), byteLength >>> alignLog2, offsetof<i32[]>("length_"));
|
||||
// if (flags & RuntimeFlags.VALUE_MANAGED) {
|
||||
// let cur = buffer;
|
||||
// let end = cur + <usize>byteLength;
|
||||
// while (cur < end) {
|
||||
// let ref = load<usize>(cur);
|
||||
// if (ref) {
|
||||
// if (isDefined(__ref_link)) __ref_link(ref, array);
|
||||
// else if (isDefined(__ref_retain)) __ref_retain(ref);
|
||||
// else assert(false);
|
||||
// }
|
||||
// cur += sizeof<usize>();
|
||||
// }
|
||||
// }
|
||||
// return array;
|
||||
// }
|
||||
|
||||
/** Retains a managed object externally, making sure that it doesn't become collected. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
@ -144,7 +184,7 @@ export namespace runtime {
|
||||
}
|
||||
}
|
||||
|
||||
/** Performs a full garbage collection cycle.*/
|
||||
/** Performs a full garbage collection cycle. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function collect(): void {
|
||||
@ -164,6 +204,7 @@ export namespace runtime {
|
||||
|
||||
class Root {}
|
||||
|
||||
/** A root object to retain managed objects on externally. */
|
||||
// @ts-ignore
|
||||
@lazy
|
||||
var ROOT = new Root();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "allocator/tlsf";
|
||||
import "collector/itcm";
|
||||
|
||||
export { runtime };
|
||||
export { runtime as $ };
|
||||
|
@ -1,7 +1,7 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { MAX_SIZE_32 } from "./util/allocator";
|
||||
import { HEADER, HEADER_SIZE } from "./util/runtime";
|
||||
import { HEADER, HEADER_SIZE, allocate, register } from "./util/runtime";
|
||||
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
@ -11,21 +11,17 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
@lazy static readonly MAX_LENGTH: i32 = (MAX_SIZE_32 - HEADER_SIZE) >> alignof<u16>();
|
||||
|
||||
get length(): i32 {
|
||||
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize >> 1;
|
||||
}
|
||||
|
||||
// TODO Add and handle second argument
|
||||
static fromCharCode(code: i32): String {
|
||||
var out = runtime.allocate(2);
|
||||
var out = allocate(2);
|
||||
store<u16>(out, <u16>code);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
static fromCodePoint(code: i32): String {
|
||||
assert(<u32>code <= 0x10FFFF);
|
||||
var sur = code > 0xFFFF;
|
||||
var out = runtime.allocate((i32(sur) + 1) << 1);
|
||||
var out = allocate((i32(sur) + 1) << 1);
|
||||
if (!sur) {
|
||||
store<u16>(out, <u16>code);
|
||||
} else {
|
||||
@ -34,15 +30,25 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
let lo: u32 = (code & 0x3FF) + 0xDC00;
|
||||
store<u32>(out, (hi << 16) | lo);
|
||||
}
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
// @unsafe
|
||||
// constructor(length: i32) {
|
||||
// return changetype<String>(register(allocate(<usize>length << 1), __runtime_id<String>()));
|
||||
// }
|
||||
|
||||
get length(): i32 {
|
||||
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize >> 1;
|
||||
}
|
||||
|
||||
@operator("[]") charAt(pos: i32): String {
|
||||
assert(this !== null);
|
||||
if (<u32>pos >= <u32>this.length) return changetype<String>("");
|
||||
var out = runtime.allocate(2);
|
||||
var out = allocate(2);
|
||||
store<u16>(out, load<u16>(changetype<usize>(this) + (<usize>pos << 1)));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
charCodeAt(pos: i32): i32 {
|
||||
@ -69,10 +75,10 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
var otherSize: isize = other.length << 1;
|
||||
var outSize: usize = thisSize + otherSize;
|
||||
if (outSize == 0) return changetype<String>("");
|
||||
var out = runtime.allocate(outSize);
|
||||
var out = allocate(outSize);
|
||||
memory.copy(out, changetype<usize>(this), thisSize);
|
||||
memory.copy(out + thisSize, changetype<usize>(other), otherSize);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
endsWith(searchString: String, endPosition: i32 = String.MAX_LENGTH): bool {
|
||||
@ -188,9 +194,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
if (intStart < 0) intStart = max(size + intStart, 0);
|
||||
var resultLength = min(max(end, 0), size - intStart);
|
||||
if (resultLength <= 0) return changetype<String>("");
|
||||
var out = runtime.allocate(resultLength << 1);
|
||||
var out = allocate(resultLength << 1);
|
||||
memory.copy(out, changetype<usize>(this) + intStart, resultLength);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
||||
@ -203,9 +209,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
len = toPos - fromPos;
|
||||
if (!len) return changetype<String>("");
|
||||
if (!fromPos && toPos == this.length << 1) return this;
|
||||
var out = runtime.allocate(len);
|
||||
var out = allocate(len);
|
||||
memory.copy(out, changetype<usize>(this) + fromPos, len);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
trim(): String {
|
||||
@ -231,9 +237,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
}
|
||||
if (!size) return changetype<String>("");
|
||||
if (!start && size == length << 1) return this;
|
||||
var out = runtime.allocate(size);
|
||||
var out = allocate(size);
|
||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
@inline
|
||||
@ -261,9 +267,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
if (!offset) return this;
|
||||
size -= offset;
|
||||
if (!size) return changetype<String>("");
|
||||
var out = runtime.allocate(size);
|
||||
var out = allocate(size);
|
||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
trimEnd(): String {
|
||||
@ -280,9 +286,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
}
|
||||
if (!size) return changetype<String>("");
|
||||
if (size == originalSize) return this;
|
||||
var out = runtime.allocate(size);
|
||||
var out = allocate(size);
|
||||
memory.copy(out, changetype<usize>(this), size);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
padStart(targetLength: i32, padString: string = " "): String {
|
||||
@ -292,7 +298,7 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
var padSize = <usize>padString.length << 1;
|
||||
if (targetSize < thisSize || !padSize) return this;
|
||||
var prependSize = targetSize - thisSize;
|
||||
var out = runtime.allocate(targetSize);
|
||||
var out = allocate(targetSize);
|
||||
if (prependSize > padSize) {
|
||||
let repeatCount = (prependSize - 2) / padSize;
|
||||
let restBase = repeatCount * padSize;
|
||||
@ -303,7 +309,7 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
memory.copy(out, changetype<usize>(padString), prependSize);
|
||||
}
|
||||
memory.copy(out + prependSize, changetype<usize>(this), thisSize);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
padEnd(targetLength: i32, padString: string = " "): String {
|
||||
@ -313,7 +319,7 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
var padSize = <usize>padString.length << 1;
|
||||
if (targetSize < thisSize || !padSize) return this;
|
||||
var appendSize = targetSize - thisSize;
|
||||
var out = runtime.allocate(targetSize);
|
||||
var out = allocate(targetSize);
|
||||
memory.copy(out, changetype<usize>(this), thisSize);
|
||||
if (appendSize > padSize) {
|
||||
let repeatCount = (appendSize - 2) / padSize;
|
||||
@ -324,7 +330,7 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
} else {
|
||||
memory.copy(out + thisSize, changetype<usize>(padString), appendSize);
|
||||
}
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
repeat(count: i32 = 0): String {
|
||||
@ -338,9 +344,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
if (count == 0 || !length) return changetype<String>("");
|
||||
if (count == 1) return this;
|
||||
var out = runtime.allocate((length * count) << 1);
|
||||
var out = allocate((length * count) << 1);
|
||||
memory.repeat(out, changetype<usize>(this), <usize>length << 1, count);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
slice(beginIndex: i32, endIndex: i32 = i32.MAX_VALUE): String {
|
||||
@ -349,9 +355,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
var end = endIndex < 0 ? max(endIndex + len, 0) : min(endIndex, len);
|
||||
len = end - begin;
|
||||
if (len <= 0) return changetype<String>("");
|
||||
var out = runtime.allocate(len << 1);
|
||||
var out = allocate(len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>begin << 1), <usize>len << 1);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
split(separator: String | null = null, limit: i32 = i32.MAX_VALUE): String[] {
|
||||
@ -368,10 +374,10 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
let result = changetype<String[]>(runtime.newArray(length, alignof<String>(), __runtime_id<String[]>()));
|
||||
let resultStart = changetype<ArrayBufferView>(result).dataStart;
|
||||
for (let i: isize = 0; i < length; ++i) {
|
||||
let charStr = runtime.allocate(2);
|
||||
let charStr = 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, __runtime_id<String>());
|
||||
register(charStr, __runtime_id<String>());
|
||||
if (isManaged<String>()) {
|
||||
if (isDefined(__ref_link)) __ref_link(changetype<usize>(charStr), changetype<usize>(result));
|
||||
if (isDefined(__ref_retain)) __ref_retain(changetype<usize>(charStr));
|
||||
@ -388,9 +394,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
while ((end = this.indexOf(separator!, start)) != -1) {
|
||||
let len = end - start;
|
||||
if (len > 0) {
|
||||
let out = runtime.allocate(<usize>len << 1);
|
||||
let out = allocate(<usize>len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||
result.push(changetype<String>(runtime.register(out, __runtime_id<String>())));
|
||||
result.push(changetype<String>(register(out, __runtime_id<String>())));
|
||||
} else {
|
||||
result.push(changetype<String>(""));
|
||||
}
|
||||
@ -404,9 +410,9 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
}
|
||||
var len = length - start;
|
||||
if (len > 0) {
|
||||
let out = runtime.allocate(<usize>len << 1);
|
||||
let out = allocate(<usize>len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||
result.push(changetype<String>(runtime.register(out, __runtime_id<String>())));
|
||||
result.push(changetype<String>(register(out, __runtime_id<String>())));
|
||||
} else {
|
||||
result.push(changetype<String>(""));
|
||||
}
|
||||
@ -478,10 +484,10 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
}
|
||||
}
|
||||
assert(ptrPos == len);
|
||||
var out = runtime.allocate(bufPos);
|
||||
var out = allocate(bufPos);
|
||||
memory.copy(changetype<usize>(out), buf, bufPos);
|
||||
memory.free(buf);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
toUTF8(): usize {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { allocate, register } from "./util/runtime";
|
||||
import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort";
|
||||
import { E_INDEXOUTOFRANGE } from "./util/error";
|
||||
import { __runtime_id } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
export class Int8Array extends ArrayBufferView {
|
||||
[key: number]: i8;
|
||||
@ -961,13 +962,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 = runtime.allocate(offsetof<TArray>());
|
||||
var out = 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 changetype<TArray>(runtime.register(out, __runtime_id<TArray>()));
|
||||
return changetype<TArray>(register(out, __runtime_id<TArray>()));
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { runtime, __runtime_id } from "../runtime";
|
||||
import { ArrayBufferView } from "../arraybuffer";
|
||||
import { allocate, register, discard } from "./runtime";
|
||||
import { CharCode } from "./string";
|
||||
import { __runtime_id } from "../runtime";
|
||||
import { ArrayBufferView } from "../arraybuffer";
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@inline
|
||||
@ -263,10 +264,10 @@ export function utoa32(value: u32): String {
|
||||
if (!value) return "0";
|
||||
|
||||
var decimals = decimalCount32(value);
|
||||
var out = runtime.allocate(decimals << 1);
|
||||
var out = allocate(decimals << 1);
|
||||
|
||||
utoa32_core(changetype<usize>(out), value, decimals);
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function itoa32(value: i32): String {
|
||||
@ -276,12 +277,12 @@ export function itoa32(value: i32): String {
|
||||
if (sign) value = -value;
|
||||
|
||||
var decimals = decimalCount32(value) + u32(sign);
|
||||
var out = runtime.allocate(decimals << 1);
|
||||
var out = allocate(decimals << 1);
|
||||
|
||||
utoa32_core(changetype<usize>(out), value, decimals);
|
||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function utoa64(value: u64): String {
|
||||
@ -291,14 +292,14 @@ export function utoa64(value: u64): String {
|
||||
if (value <= u32.MAX_VALUE) {
|
||||
let val32 = <u32>value;
|
||||
let decimals = decimalCount32(val32);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
out = allocate(decimals << 1);
|
||||
utoa32_core(out, val32, decimals);
|
||||
} else {
|
||||
let decimals = decimalCount64(value);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
out = allocate(decimals << 1);
|
||||
utoa64_core(changetype<usize>(out), value, decimals);
|
||||
}
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function itoa64(value: i64): String {
|
||||
@ -311,16 +312,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 = runtime.allocate(decimals << 1);
|
||||
out = allocate(decimals << 1);
|
||||
utoa32_core(changetype<usize>(out), val32, decimals);
|
||||
} else {
|
||||
let decimals = decimalCount64(value) + u32(sign);
|
||||
out = runtime.allocate(decimals << 1);
|
||||
out = allocate(decimals << 1);
|
||||
utoa64_core(changetype<usize>(out), value, decimals);
|
||||
}
|
||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
return changetype<String>(register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function itoa<T extends number>(value: T): String {
|
||||
@ -625,10 +626,10 @@ export function dtoa(value: f64): String {
|
||||
if (isNaN<f64>(value)) return "NaN";
|
||||
return select<String>("-Infinity", "Infinity", value < 0);
|
||||
}
|
||||
var temp = runtime.allocate(MAX_DOUBLE_LENGTH << 1);
|
||||
var temp = allocate(MAX_DOUBLE_LENGTH << 1);
|
||||
var length = dtoa_core(temp, value);
|
||||
var result = changetype<String>(temp).substring(0, length); // registers
|
||||
runtime.discard(temp);
|
||||
discard(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,20 @@ export function adjust(payloadSize: usize): usize {
|
||||
return <usize>1 << <usize>(<u32>32 - clz<u32>(payloadSize + HEADER_SIZE - 1));
|
||||
}
|
||||
|
||||
/** Allocates the memory necessary to represent a managed object of the specified size. */
|
||||
// @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;
|
||||
}
|
||||
return changetype<usize>(header) + HEADER_SIZE;
|
||||
}
|
||||
|
||||
/** Reallocates the memory of a managed object that turned out to be too small or too large. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
@ -91,3 +105,53 @@ export function reallocate(ref: usize, newPayloadSize: usize): usize {
|
||||
header.payloadSize = newPayloadSize;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/** Discards the memory of a managed object that hasn't been registered yet. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/** Registers a managed object of the kind represented by the specified runtime id. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function register(ref: usize, id: 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 = id;
|
||||
} else {
|
||||
changetype<HEADER>(ref - HEADER_SIZE).classId = id;
|
||||
}
|
||||
if (isDefined(__ref_register)) __ref_register(ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
/** Allocates and registers, but doesn't initialize the data of, a new `Array` of the specified length and element alignment. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function newArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {
|
||||
// TODO: This API isn't great, but the compiler requires it for array literals anyway,
|
||||
// that is when an array literal is encountered and its data is static, this function is
|
||||
// called and the static buffer provided as `data`. This function can also be used to
|
||||
// create typed arrays in that `Array` also implements `ArrayBufferView` but has an
|
||||
// additional `.length_` property that remains unused overhead for typed arrays.
|
||||
var array = newObject(offsetof<i32[]>(), id);
|
||||
var bufferSize = <u32>length << alignLog2;
|
||||
var buffer = newArrayBuffer(bufferSize);
|
||||
changetype<ArrayBufferView>(array).data = changetype<ArrayBuffer>(buffer); // links
|
||||
changetype<ArrayBufferView>(array).dataStart = buffer;
|
||||
changetype<ArrayBufferView>(array).dataLength = bufferSize;
|
||||
store<i32>(changetype<usize>(array), length, offsetof<i32[]>("length_"));
|
||||
if (data) memory.copy(buffer, data, <usize>bufferSize);
|
||||
return array;
|
||||
}
|
||||
|
Reference in New Issue
Block a user