mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-22 11:11:43 +00:00
directize
This commit is contained in:
@ -1,8 +1,9 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { runtime, classId } from "./runtime";
|
||||
import { ArrayBuffer, ArrayBufferView } from "./arraybuffer";
|
||||
import { MAX_BYTELENGTH } from "./util/runtime";
|
||||
import { COMPARATOR, SORT } from "./util/sort";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { ArrayBuffer, ArrayBufferView } from "./arraybuffer";
|
||||
import { itoa, dtoa, itoa_stream, dtoa_stream, MAX_DOUBLE_LENGTH } from "./util/number";
|
||||
import { isArray as builtin_isArray } from "./builtins";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_EMPTYARRAY, E_HOLEYARRAY } from "./util/error";
|
||||
@ -10,7 +11,7 @@ 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>(runtime.MAX_BYTELENGTH >>> alignLog2)) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (<u32>minCapacity > <u32>(MAX_BYTELENGTH >>> alignLog2)) throw new RangeError(E_INVALIDLENGTH);
|
||||
let oldData = array.data;
|
||||
let newByteLength = minCapacity << alignLog2;
|
||||
let newData = runtime.reallocate(changetype<usize>(oldData), <usize>newByteLength); // registers on move
|
||||
@ -40,8 +41,8 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
|
||||
static create<T>(capacity: i32 = 0): Array<T> {
|
||||
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>()));
|
||||
if (<u32>capacity > <u32>MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
var array = changetype<Array<T>>(runtime.makeArray(capacity, __runtime_id<Array<T>>(), alignof<T>()));
|
||||
memory.fill(array.dataStart, 0, <usize>array.dataLength);
|
||||
array.length_ = 0; // !
|
||||
return array;
|
||||
@ -231,7 +232,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 = changetype<Array<T>>(runtime.makeArray(thisLen + otherLen, classId<Array<T>>(), alignof<T>()));
|
||||
var out = changetype<Array<T>>(runtime.makeArray(thisLen + otherLen, __runtime_id<Array<T>>(), alignof<T>()));
|
||||
var outStart = out.dataStart;
|
||||
var thisSize = <usize>thisLen << alignof<T>();
|
||||
if (isManaged<T>()) {
|
||||
@ -319,7 +320,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 = changetype<Array<U>>(runtime.makeArray(length, classId<Array<U>>(), alignof<U>()));
|
||||
var out = changetype<Array<U>>(runtime.makeArray(length, __runtime_id<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 +346,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
}
|
||||
|
||||
filter(callbackfn: (value: T, index: i32, array: Array<T>) => bool): Array<T> {
|
||||
var result = changetype<Array<T>>(runtime.makeArray(0, classId<Array<T>>(), alignof<T>()));
|
||||
var result = changetype<Array<T>>(runtime.makeArray(0, __runtime_id<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 +434,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 = changetype<Array<T>>(runtime.makeArray(length, classId<Array<T>>(), alignof<T>()));
|
||||
var slice = changetype<Array<T>>(runtime.makeArray(length, __runtime_id<Array<T>>(), alignof<T>()));
|
||||
var sliceBase = slice.dataStart;
|
||||
var thisBase = this.dataStart + (<usize>begin << alignof<T>());
|
||||
if (isManaged<T>()) {
|
||||
@ -465,7 +466,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 = changetype<Array<T>>(runtime.makeArray(deleteCount, classId<Array<T>>(), alignof<T>()));
|
||||
var result = changetype<Array<T>>(runtime.makeArray(deleteCount, __runtime_id<Array<T>>(), alignof<T>()));
|
||||
var resultStart = result.dataStart;
|
||||
var thisStart = this.dataStart;
|
||||
var thisBase = thisStart + (<usize>start << alignof<T>());
|
||||
@ -595,7 +596,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
runtime.discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_int(separator: string = ","): string {
|
||||
@ -632,7 +633,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
runtime.discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_flt(separator: string = ","): string {
|
||||
@ -677,7 +678,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
runtime.discard(result);
|
||||
return trimmed; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_str(separator: string = ","): string {
|
||||
@ -723,7 +724,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
<usize>changetype<string>(value).length << 1
|
||||
);
|
||||
}
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
private join_arr(separator: string = ","): string {
|
||||
@ -795,7 +796,7 @@ export class Array<T> extends ArrayBufferView {
|
||||
runtime.discard(result);
|
||||
return out; // registered in .substring
|
||||
}
|
||||
return changetype<string>(runtime.register(result, classId<string>()));
|
||||
return changetype<string>(runtime.register(result, __runtime_id<string>()));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
@ -804,8 +805,8 @@ export class Array<T> extends ArrayBufferView {
|
||||
|
||||
// GC integration
|
||||
|
||||
@unsafe private __iterate(fn: (ref: usize) => void): void {
|
||||
fn(changetype<usize>(this.data));
|
||||
@unsafe private __traverse(): void {
|
||||
__ref_mark(changetype<usize>(this.data));
|
||||
if (isManaged<T>()) {
|
||||
let cur = this.dataStart;
|
||||
let end = cur + <usize>this.dataLength;
|
||||
@ -813,12 +814,12 @@ export class Array<T> extends ArrayBufferView {
|
||||
let val = load<usize>(cur);
|
||||
if (isNullable<T>()) {
|
||||
if (val) {
|
||||
fn(val);
|
||||
call_indirect(classId<T>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<T>(), val);
|
||||
}
|
||||
} else {
|
||||
fn(val);
|
||||
call_indirect(classId<T>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<T>(), val);
|
||||
}
|
||||
cur += sizeof<usize>();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { runtime, HEADER, HEADER_SIZE, classId } from "./runtime";
|
||||
import { HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./util/runtime";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
export abstract class ArrayBufferView {
|
||||
@ -8,7 +9,7 @@ export abstract class ArrayBufferView {
|
||||
@unsafe dataLength: u32;
|
||||
|
||||
protected constructor(length: i32, alignLog2: i32) {
|
||||
if (<u32>length > <u32>runtime.MAX_BYTELENGTH >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
|
||||
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);
|
||||
@ -50,24 +51,24 @@ export abstract class ArrayBufferView {
|
||||
}
|
||||
|
||||
constructor(length: i32) {
|
||||
if (<u32>length > <u32>runtime.MAX_BYTELENGTH) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (<u32>length > <u32>MAX_BYTELENGTH) throw new RangeError(E_INVALIDLENGTH);
|
||||
var buffer = runtime.allocate(<usize>length);
|
||||
memory.fill(changetype<usize>(buffer), 0, <usize>length);
|
||||
return changetype<ArrayBuffer>(runtime.register(buffer, classId<ArrayBuffer>()));
|
||||
return changetype<ArrayBuffer>(runtime.register(buffer, __runtime_id<ArrayBuffer>()));
|
||||
}
|
||||
|
||||
get byteLength(): i32 {
|
||||
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize;
|
||||
}
|
||||
|
||||
slice(begin: i32 = 0, end: i32 = runtime.MAX_BYTELENGTH): ArrayBuffer {
|
||||
slice(begin: i32 = 0, end: i32 = 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 = runtime.allocate(outSize);
|
||||
memory.copy(out, changetype<usize>(this) + <usize>begin, outSize);
|
||||
return changetype<ArrayBuffer>(runtime.register(out, classId<ArrayBuffer>()));
|
||||
return changetype<ArrayBuffer>(runtime.register(out, __runtime_id<ArrayBuffer>()));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
@ -176,6 +176,10 @@ export declare function unchecked<T>(expr: T): T;
|
||||
@builtin
|
||||
export declare function call_indirect<T>(target: void, ...args: void[]): T;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function call_direct<T>(target: void, ...args: void[]): T;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function instantiate<T>(...args: void[]): T;
|
||||
|
@ -21,6 +21,9 @@ Tracing
|
||||
* **__ref_unlink**(ref: `usize`, parentRef: `usize`): `void`<br />
|
||||
Unlinks a reference from a parent that was referencing it. Implementation is optional.
|
||||
|
||||
* **__ref_mark**(ref: `usize`): `void`<br />
|
||||
Marks a reference as being reachable so it doesn't become sweeped.
|
||||
|
||||
Reference counting
|
||||
------------------
|
||||
|
||||
|
@ -29,3 +29,9 @@ function __ref_link(ref: usize, parentRef: usize): void {
|
||||
function __ref_unlink(ref: usize, parentRef: usize): void {
|
||||
if (TRACE) trace("dummy.unlink", 2, ref, parentRef);
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@global @unsafe
|
||||
function __ref_mark(ref: usize): void {
|
||||
if (TRACE) trace("dummy.mark", 1, ref);
|
||||
}
|
||||
|
1
std/assembly/collector/index.d.ts
vendored
1
std/assembly/collector/index.d.ts
vendored
@ -5,6 +5,7 @@ declare function __ref_register(ref: usize): void;
|
||||
// tracing
|
||||
declare function __ref_link(ref: usize, parentRef: usize): void;
|
||||
declare function __ref_unlink(ref: usize, parentRef: usize): void;
|
||||
declare function __ref_mark(ref: usize): void;
|
||||
|
||||
// reference counting
|
||||
declare function __ref_retain(ref: usize): void;
|
||||
|
@ -4,7 +4,8 @@
|
||||
@inline
|
||||
const TRACE = isDefined(GC_TRACE);
|
||||
|
||||
import { iterateRoots, HEADER_SIZE } from "../runtime";
|
||||
import { HEADER_SIZE } from "../util/runtime";
|
||||
import { __gc_mark_roots, __gc_mark_members } from "../gc";
|
||||
|
||||
/** Collector states. */
|
||||
const enum State {
|
||||
@ -155,10 +156,7 @@ function step(): void {
|
||||
}
|
||||
case State.IDLE: {
|
||||
if (TRACE) trace("itcm~step/IDLE");
|
||||
iterateRoots((ref: usize): void => {
|
||||
var obj = refToObj(ref);
|
||||
if (obj.color == white) obj.makeGray();
|
||||
});
|
||||
__gc_mark_roots();
|
||||
state = State.MARK;
|
||||
if (TRACE) trace("itcm~state = MARK");
|
||||
break;
|
||||
@ -166,21 +164,14 @@ function step(): void {
|
||||
case State.MARK: {
|
||||
obj = iter.next;
|
||||
if (obj !== toSpace) {
|
||||
if (TRACE) trace("itcm~step/MARK iterate", 1, objToRef(obj));
|
||||
if (TRACE) trace("itcm~step/MARK", 1, objToRef(obj));
|
||||
iter = obj;
|
||||
obj.color = i32(!white);
|
||||
// CLASS~iterate(ref, fn)
|
||||
call_indirect(obj.classId, objToRef(obj), (ref: usize): void => {
|
||||
trace(" iter", 1, ref);
|
||||
var obj = refToObj(ref);
|
||||
if (obj.color == white) obj.makeGray();
|
||||
});
|
||||
// TODO: directize through __gc_mark_members
|
||||
call_indirect(obj.classId, objToRef(obj)); // CLASS~traverse(ref)
|
||||
} else {
|
||||
__gc_mark_roots();
|
||||
if (TRACE) trace("itcm~step/MARK finish");
|
||||
iterateRoots((ref: usize): void => {
|
||||
var obj = refToObj(ref);
|
||||
if (obj.color == white) obj.makeGray();
|
||||
});
|
||||
obj = iter.next;
|
||||
if (obj === toSpace) {
|
||||
let from = fromSpace;
|
||||
@ -257,7 +248,9 @@ export function __ref_link(ref: usize, parentRef: usize): void {
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
// @global @unsafe
|
||||
// export function __ref_unlink(ref: usize, parentRef: usize): void {
|
||||
// if (TRACE) trace("itcm.unlink", 2, ref, parentRef);
|
||||
// }
|
||||
@global @unsafe
|
||||
export function __ref_mark(ref: usize): void {
|
||||
if (TRACE) trace("itcm.mark", 1, ref);
|
||||
var obj = refToObj(ref);
|
||||
if (obj.color == white) obj.makeGray();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { runtime } from "./runtime";
|
||||
import { MAX_BYTELENGTH } from "./util/runtime";
|
||||
import { ArrayBuffer } from "./arraybuffer";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH } from "./util/error";
|
||||
|
||||
@ -13,11 +13,10 @@ export class DataView {
|
||||
constructor(
|
||||
buffer: ArrayBuffer,
|
||||
byteOffset: i32 = 0,
|
||||
byteLength: i32 = i32.MIN_VALUE // FIXME: TS2304: Cannot find name 'buffer'.
|
||||
byteLength: i32 = buffer.byteLength
|
||||
) {
|
||||
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; // FIXME
|
||||
if (
|
||||
i32(<u32>byteLength > <u32>runtime.MAX_BYTELENGTH) |
|
||||
i32(<u32>byteLength > <u32>MAX_BYTELENGTH) |
|
||||
i32(<u32>byteOffset + byteLength > <u32>buffer.byteLength)
|
||||
) throw new RangeError(E_INVALIDLENGTH);
|
||||
this.data = buffer; // links
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { runtime, classId, HEADER, HEADER_SIZE } from "./runtime";
|
||||
import { HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./util/runtime";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
|
||||
|
||||
// NOTE: DO NOT USE YET!
|
||||
@ -10,7 +11,7 @@ export class FixedArray<T> {
|
||||
[key: number]: T;
|
||||
|
||||
constructor(length: i32) {
|
||||
if (<u32>length > <u32>runtime.MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (<u32>length > <u32>MAX_BYTELENGTH >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
|
||||
if (isReference<T>()) {
|
||||
if (!isNullable<T>()) {
|
||||
if (length) throw new Error(E_HOLEYARRAY);
|
||||
@ -19,7 +20,7 @@ export class FixedArray<T> {
|
||||
var outSize = <usize>length << alignof<T>();
|
||||
var out = runtime.allocate(outSize);
|
||||
memory.fill(out, 0, outSize);
|
||||
return changetype<FixedArray<T>>(runtime.register(out, classId<FixedArray<T>>()));
|
||||
return changetype<FixedArray<T>>(runtime.register(out, __runtime_id<FixedArray<T>>()));
|
||||
}
|
||||
|
||||
get length(): i32 {
|
||||
@ -71,7 +72,7 @@ export class FixedArray<T> {
|
||||
|
||||
// GC integration
|
||||
|
||||
@unsafe private __iterate(fn: (ref: usize) => void): void {
|
||||
@unsafe private __traverse(): void {
|
||||
if (isManaged<T>()) {
|
||||
let cur = changetype<usize>(this);
|
||||
let end = cur + changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize;
|
||||
@ -79,12 +80,12 @@ export class FixedArray<T> {
|
||||
let val = load<usize>(cur);
|
||||
if (isNullable<T>()) {
|
||||
if (val) {
|
||||
fn(val);
|
||||
call_indirect(classId<T>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<T>(), val);
|
||||
}
|
||||
} else {
|
||||
fn(val);
|
||||
call_indirect(classId<T>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<T>(), val);
|
||||
}
|
||||
cur += sizeof<usize>();
|
||||
}
|
||||
|
@ -2,9 +2,19 @@
|
||||
|
||||
import { E_NOTIMPLEMENTED } from "./util/error";
|
||||
|
||||
/** Marks root objects. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
export declare function __gc_mark_roots(): void;
|
||||
|
||||
/** Marks class members. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
export declare function __gc_mark_members(classId: u32, ref: usize): void;
|
||||
|
||||
// @ts-ignore
|
||||
@lazy
|
||||
var GC_ROOT = new Set<usize>();
|
||||
var ROOT = new Set<usize>();
|
||||
|
||||
/** Garbage collector interface. */
|
||||
export namespace gc {
|
||||
@ -24,7 +34,7 @@ export namespace gc {
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function retain(ref: usize): void {
|
||||
var root = GC_ROOT;
|
||||
var root = ROOT;
|
||||
if (!root.has(ref)) {
|
||||
root.add(ref);
|
||||
if (implemented) {
|
||||
@ -38,7 +48,7 @@ export namespace gc {
|
||||
// @ts-ignore: decorator
|
||||
@unsafe
|
||||
export function release(ref: usize): void {
|
||||
var root = GC_ROOT;
|
||||
var root = ROOT;
|
||||
if (root.has(ref)) {
|
||||
root.delete(ref);
|
||||
if (implemented) {
|
||||
|
2
std/assembly/index.d.ts
vendored
2
std/assembly/index.d.ts
vendored
@ -118,6 +118,8 @@ declare function changetype<T>(value: any): T;
|
||||
declare function unchecked<T>(value: T): T;
|
||||
/** Emits a `call_indirect` instruction, calling the specified function in the function table by index with the specified arguments. Does result in a runtime error if the arguments do not match the called function. */
|
||||
declare function call_indirect<T>(target: Function | u32, ...args: any[]): T;
|
||||
/** Emits a `call` instruction, calling the specified function in the function table directly with the specified arguments. Function index must be a compile-time constant. */
|
||||
declare function call_direct<T>(target: Function | u32, ...args: any[]): T;
|
||||
/** Instantiates a new instance of `T` using the specified constructor arguments. */
|
||||
declare function instantiate<T>(...args: any[]): T;
|
||||
/** Tests if a 32-bit or 64-bit float is `NaN`. */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { HASH } from "./util/hash";
|
||||
import { classId } from "./runtime";
|
||||
import { __runtime_id } from "./runtime";
|
||||
|
||||
// A deterministic hash map based on CloseTable from https://github.com/jorendorff/dht
|
||||
|
||||
@ -268,10 +268,10 @@ export class Map<K,V> {
|
||||
|
||||
// GC integration
|
||||
|
||||
@unsafe private __iterate(fn: (ref: usize) => void): void {
|
||||
fn(changetype<usize>(this.buckets));
|
||||
@unsafe private __traverse(): void {
|
||||
__ref_mark(changetype<usize>(this.buckets));
|
||||
var entries = this.entries;
|
||||
fn(changetype<usize>(entries));
|
||||
__ref_mark(changetype<usize>(entries));
|
||||
if (isManaged<K>() || isManaged<V>()) {
|
||||
let cur = changetype<usize>(entries);
|
||||
let end = cur + <usize>this.entriesOffset * ENTRY_SIZE<K,V>();
|
||||
@ -282,24 +282,24 @@ export class Map<K,V> {
|
||||
let val = changetype<usize>(entry.key);
|
||||
if (isNullable<K>()) {
|
||||
if (val) {
|
||||
fn(val);
|
||||
call_indirect(classId<K>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<K>(), val);
|
||||
}
|
||||
} else {
|
||||
fn(val);
|
||||
call_indirect(classId<K>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<K>(), val);
|
||||
}
|
||||
}
|
||||
if (isManaged<V>()) {
|
||||
let val = changetype<usize>(entry.value);
|
||||
if (isNullable<V>()) {
|
||||
if (val) {
|
||||
fn(val);
|
||||
call_indirect(classId<V>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<V>(), val);
|
||||
}
|
||||
} else {
|
||||
fn(val);
|
||||
call_indirect(classId<V>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<V>(), val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +1,18 @@
|
||||
// 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 { AL_MASK, MAX_SIZE_32 } from "./util/allocator";
|
||||
import { HEADER, HEADER_SIZE, HEADER_MAGIC } from "./util/runtime";
|
||||
import { HEAP_BASE, memory } from "./memory";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
/**
|
||||
* The common runtime object header prepended to all managed objects. Has a size of 16 bytes in
|
||||
* WASM32 and contains a classId (e.g. for instanceof checks), the allocation size (e.g. for
|
||||
* .byteLength and .length computation) and additional reserved fields to be used by GC. If no
|
||||
* GC is present, the HEADER is cut into half excluding the reserved fields, as indicated by
|
||||
* HEADER_SIZE.
|
||||
*/
|
||||
@unmanaged export class HEADER {
|
||||
/** Unique id of the respective class or a magic value if not yet registered.*/
|
||||
classId: u32;
|
||||
/** Size of the allocated payload. */
|
||||
payloadSize: u32;
|
||||
/** Reserved field for use by GC. Only present if GC is. */
|
||||
reserved1: usize; // itcm: tagged next
|
||||
/** Reserved field for use by GC. Only present if GC is. */
|
||||
reserved2: usize; // itcm: prev
|
||||
}
|
||||
|
||||
/** Common runtime header size. */
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
export const HEADER_SIZE: usize = isDefined(__ref_collect)
|
||||
? (offsetof<HEADER>( ) + AL_MASK) & ~AL_MASK // full header if GC is present
|
||||
: (offsetof<HEADER>("reserved1") + AL_MASK) & ~AL_MASK; // half header if GC is absent
|
||||
|
||||
/** Common runtime header magic. Used to assert registered/unregistered status. */
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
export const HEADER_MAGIC: u32 = 0xA55E4B17;
|
||||
|
||||
/** Gets the computed unique class id of a class type. */
|
||||
/** Gets the computed unique id of a class type. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
export declare function classId<T>(): u32;
|
||||
|
||||
/** Iterates over all root objects of a reference type. */
|
||||
// @ts-ignore: decorator
|
||||
@unsafe @builtin
|
||||
export declare function iterateRoots(fn: (ref: usize) => void): void;
|
||||
export declare function __runtime_id<T>(): u32;
|
||||
|
||||
/** Runtime implementation. */
|
||||
export namespace runtime {
|
||||
|
||||
/** Maximum byte length of any buffer-like object. */
|
||||
// @ts-ignore
|
||||
@lazy
|
||||
export const MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
||||
|
||||
/** 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:
|
||||
@ -152,10 +112,10 @@ export namespace runtime {
|
||||
|
||||
// @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);
|
||||
export function makeArray(capacity: i32, id: u32, alignLog2: usize, source: usize = 0): usize {
|
||||
var array = runtime.register(runtime.allocate(offsetof<i32[]>()), id);
|
||||
var bufferSize = <usize>capacity << alignLog2;
|
||||
var buffer = runtime.register(runtime.allocate(<usize>capacity << alignLog2), classId<ArrayBuffer>());
|
||||
var buffer = runtime.register(runtime.allocate(<usize>capacity << alignLog2), __runtime_id<ArrayBuffer>());
|
||||
changetype<ArrayBufferView>(array).data = changetype<ArrayBuffer>(buffer); // links
|
||||
changetype<ArrayBufferView>(array).dataStart = buffer;
|
||||
changetype<ArrayBufferView>(array).dataLength = bufferSize;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { HASH } from "./util/hash";
|
||||
import { classId } from "./runtime";
|
||||
import { __runtime_id } from "./runtime";
|
||||
|
||||
// A deterministic hash set based on CloseTable from https://github.com/jorendorff/dht
|
||||
|
||||
@ -198,10 +198,10 @@ export class Set<K> {
|
||||
|
||||
// GC integration
|
||||
|
||||
@unsafe private __iterate(fn: (ref: usize) => void): void {
|
||||
fn(changetype<usize>(this.buckets));
|
||||
@unsafe private __traverse(): void {
|
||||
__ref_mark(changetype<usize>(this.buckets));
|
||||
var entries = this.entries;
|
||||
fn(changetype<usize>(entries));
|
||||
__ref_mark(changetype<usize>(entries));
|
||||
if (isManaged<K>()) {
|
||||
let cur = changetype<usize>(entries);
|
||||
let end = cur + <usize>this.entriesOffset * ENTRY_SIZE<K>();
|
||||
@ -211,12 +211,12 @@ export class Set<K> {
|
||||
let val = changetype<usize>(entry.key);
|
||||
if (isNullable<K>()) {
|
||||
if (val) {
|
||||
fn(val);
|
||||
call_indirect(classId<K>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<K>(), val);
|
||||
}
|
||||
} else {
|
||||
fn(val);
|
||||
call_indirect(classId<K>(), val, fn);
|
||||
__ref_mark(val);
|
||||
call_direct(__runtime_id<K>(), val);
|
||||
}
|
||||
}
|
||||
cur += ENTRY_SIZE<K>();
|
||||
|
@ -1,10 +1,11 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { MAX_SIZE_32 } from "./util/allocator";
|
||||
import { runtime, HEADER, HEADER_SIZE, classId } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { HEADER, HEADER_SIZE } from "./util/runtime";
|
||||
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
@sealed export abstract class String {
|
||||
|
||||
@ -18,7 +19,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
static fromCharCode(code: i32): String {
|
||||
var out = runtime.allocate(2);
|
||||
store<u16>(out, <u16>code);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
static fromCodePoint(code: i32): String {
|
||||
@ -33,7 +34,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
let lo: u32 = (code & 0x3FF) + 0xDC00;
|
||||
store<u32>(out, (hi << 16) | lo);
|
||||
}
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
@operator("[]") charAt(pos: i32): String {
|
||||
@ -41,7 +42,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (<u32>pos >= <u32>this.length) return changetype<String>("");
|
||||
var out = runtime.allocate(2);
|
||||
store<u16>(out, load<u16>(changetype<usize>(this) + (<usize>pos << 1)));
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
charCodeAt(pos: i32): i32 {
|
||||
@ -71,7 +72,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
var out = runtime.allocate(outSize);
|
||||
memory.copy(out, changetype<usize>(this), thisSize);
|
||||
memory.copy(out + thisSize, changetype<usize>(other), otherSize);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
endsWith(searchString: String, endPosition: i32 = String.MAX_LENGTH): bool {
|
||||
@ -183,7 +184,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (resultLength <= 0) return changetype<String>("");
|
||||
var out = runtime.allocate(resultLength << 1);
|
||||
memory.copy(out, changetype<usize>(this) + intStart, resultLength);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
||||
@ -198,7 +199,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (!fromPos && toPos == this.length << 1) return this;
|
||||
var out = runtime.allocate(len);
|
||||
memory.copy(out, changetype<usize>(this) + fromPos, len);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
trim(): String {
|
||||
@ -226,7 +227,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (!start && size == length << 1) return this;
|
||||
var out = runtime.allocate(size);
|
||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
@inline
|
||||
@ -256,7 +257,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (!size) return changetype<String>("");
|
||||
var out = runtime.allocate(size);
|
||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
trimEnd(): String {
|
||||
@ -275,7 +276,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (size == originalSize) return this;
|
||||
var out = runtime.allocate(size);
|
||||
memory.copy(out, changetype<usize>(this), size);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
padStart(targetLength: i32, padString: string = " "): String {
|
||||
@ -296,7 +297,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
memory.copy(out, changetype<usize>(padString), prependSize);
|
||||
}
|
||||
memory.copy(out + prependSize, changetype<usize>(this), thisSize);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
padEnd(targetLength: i32, padString: string = " "): String {
|
||||
@ -317,7 +318,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
} else {
|
||||
memory.copy(out + thisSize, changetype<usize>(padString), appendSize);
|
||||
}
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
repeat(count: i32 = 0): String {
|
||||
@ -333,7 +334,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (count == 1) return this;
|
||||
var out = runtime.allocate((length * count) << 1);
|
||||
memory.repeat(out, changetype<usize>(this), <usize>length << 1, count);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
slice(beginIndex: i32, endIndex: i32 = i32.MAX_VALUE): String {
|
||||
@ -344,27 +345,27 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (len <= 0) return changetype<String>("");
|
||||
var out = runtime.allocate(len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>begin << 1), <usize>len << 1);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
split(separator: String | null = null, limit: i32 = i32.MAX_VALUE): String[] {
|
||||
assert(this !== null);
|
||||
if (!limit) return changetype<String[]>(runtime.makeArray(0, classId<String[]>(), alignof<String>()));
|
||||
if (!limit) return changetype<String[]>(runtime.makeArray(0, __runtime_id<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 changetype<String[]>(runtime.makeArray(0, classId<String>(), alignof<String>()));
|
||||
if (!length) return changetype<String[]>(runtime.makeArray(0, __runtime_id<String>(), alignof<String>()));
|
||||
// split by chars
|
||||
length = min<isize>(length, <isize>limit);
|
||||
let result = changetype<String[]>(runtime.makeArray(length, classId<String[]>(), alignof<String>()));
|
||||
let result = changetype<String[]>(runtime.makeArray(length, __runtime_id<String[]>(), alignof<String>()));
|
||||
let resultStart = changetype<ArrayBufferView>(result).dataStart;
|
||||
for (let i: isize = 0; i < length; ++i) {
|
||||
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>());
|
||||
runtime.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));
|
||||
@ -372,18 +373,18 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
}
|
||||
return result;
|
||||
} else if (!length) {
|
||||
let result = changetype<String[]>(runtime.makeArray(1, classId<String[]>(), alignof<String>()));
|
||||
let result = changetype<String[]>(runtime.makeArray(1, __runtime_id<String[]>(), alignof<String>()));
|
||||
store<string>(changetype<ArrayBufferView>(result).dataStart, ""); // no need to register/link
|
||||
return result;
|
||||
}
|
||||
var result = changetype<String[]>(runtime.makeArray(0, classId<String[]>(), alignof<String>()));
|
||||
var result = changetype<String[]>(runtime.makeArray(0, __runtime_id<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 = runtime.allocate(<usize>len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||
result.push(changetype<String>(runtime.register(out, classId<String>())));
|
||||
result.push(changetype<String>(runtime.register(out, __runtime_id<String>())));
|
||||
} else {
|
||||
result.push(changetype<String>(""));
|
||||
}
|
||||
@ -391,7 +392,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
start = end + sepLen;
|
||||
}
|
||||
if (!start) {
|
||||
let result = changetype<String[]>(runtime.makeArray(1, classId<String[]>(), alignof<String>()));
|
||||
let result = changetype<String[]>(runtime.makeArray(1, __runtime_id<String[]>(), alignof<String>()));
|
||||
unchecked(result[0] = this);
|
||||
return result;
|
||||
}
|
||||
@ -399,7 +400,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
if (len > 0) {
|
||||
let out = runtime.allocate(<usize>len << 1);
|
||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||
result.push(changetype<String>(runtime.register(out, classId<String>())));
|
||||
result.push(changetype<String>(runtime.register(out, __runtime_id<String>())));
|
||||
} else {
|
||||
result.push(changetype<String>(""));
|
||||
}
|
||||
@ -474,7 +475,7 @@ import { E_INVALIDLENGTH } from "./util/error";
|
||||
var out = runtime.allocate(bufPos);
|
||||
memory.copy(changetype<usize>(out), buf, bufPos);
|
||||
memory.free(buf);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
toUTF8(): usize {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { runtime, classId } from "./runtime";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort";
|
||||
import { E_INDEXOUTOFRANGE } from "./util/error";
|
||||
@ -967,7 +967,7 @@ function SUBARRAY<TArray extends ArrayBufferView, T>(
|
||||
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, classId<TArray>()));
|
||||
return changetype<TArray>(runtime.register(out, __runtime_id<TArray>()));
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { runtime, classId } from "../runtime";
|
||||
import { runtime, __runtime_id } from "../runtime";
|
||||
import { ArrayBufferView } from "../arraybuffer";
|
||||
import { CharCode } from "./string";
|
||||
|
||||
@ -266,7 +266,7 @@ export function utoa32(value: u32): String {
|
||||
var out = runtime.allocate(decimals << 1);
|
||||
|
||||
utoa32_core(changetype<usize>(out), value, decimals);
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function itoa32(value: i32): String {
|
||||
@ -281,7 +281,7 @@ export function itoa32(value: i32): String {
|
||||
utoa32_core(changetype<usize>(out), value, decimals);
|
||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function utoa64(value: u64): String {
|
||||
@ -298,7 +298,7 @@ export function utoa64(value: u64): String {
|
||||
out = runtime.allocate(decimals << 1);
|
||||
utoa64_core(changetype<usize>(out), value, decimals);
|
||||
}
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function itoa64(value: i64): String {
|
||||
@ -320,7 +320,7 @@ export function itoa64(value: i64): String {
|
||||
}
|
||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||
|
||||
return changetype<String>(runtime.register(out, classId<String>()));
|
||||
return changetype<String>(runtime.register(out, __runtime_id<String>()));
|
||||
}
|
||||
|
||||
export function itoa<T extends number>(value: T): String {
|
||||
|
36
std/assembly/util/runtime.ts
Normal file
36
std/assembly/util/runtime.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { AL_MASK, MAX_SIZE_32 } from "./allocator";
|
||||
|
||||
/**
|
||||
* The common runtime object header prepended to all managed objects. Has a size of 16 bytes in
|
||||
* WASM32 and contains a classId (e.g. for instanceof checks), the allocation size (e.g. for
|
||||
* .byteLength and .length computation) and additional reserved fields to be used by GC. If no
|
||||
* GC is present, the HEADER is cut into half excluding the reserved fields, as indicated by
|
||||
* HEADER_SIZE.
|
||||
*/
|
||||
@unmanaged export class HEADER {
|
||||
/** Unique id of the respective class or a magic value if not yet registered.*/
|
||||
classId: u32;
|
||||
/** Size of the allocated payload. */
|
||||
payloadSize: u32;
|
||||
/** Reserved field for use by GC. Only present if GC is. */
|
||||
reserved1: usize; // itcm: tagged next
|
||||
/** Reserved field for use by GC. Only present if GC is. */
|
||||
reserved2: usize; // itcm: prev
|
||||
}
|
||||
|
||||
/** Common runtime header size. */
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
export const HEADER_SIZE: usize = isDefined(__ref_collect)
|
||||
? (offsetof<HEADER>( ) + AL_MASK) & ~AL_MASK // full header if GC is present
|
||||
: (offsetof<HEADER>("reserved1") + AL_MASK) & ~AL_MASK; // half header if GC is absent
|
||||
|
||||
/** Common runtime header magic. Used to assert registered/unregistered status. */
|
||||
// @ts-ignore: decorator
|
||||
@lazy
|
||||
export const HEADER_MAGIC: u32 = 0xA55E4B17;
|
||||
|
||||
/** Maximum byte length of any buffer-like object. */
|
||||
// @ts-ignore
|
||||
@lazy
|
||||
export const MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
Reference in New Issue
Block a user