mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-23 11:41:45 +00:00
rtti & refactoring
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { MAX_BYTELENGTH, allocate, reallocate, discard, register } from "./util/runtime";
|
||||
import { MAX_BYTELENGTH, allocate, reallocate, discard, register, NEWARRAY } from "./util/runtime";
|
||||
import { COMPARATOR, SORT } from "./util/sort";
|
||||
import { runtime, __runtime_id, __gc_mark_members } from "./runtime";
|
||||
import { __runtime_id, __gc_mark_members } 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";
|
||||
@ -42,9 +42,9 @@ 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 = changetype<Array<T>>(runtime.newArray(capacity, alignof<T>(), __runtime_id<Array<T>>()));
|
||||
memory.fill(array.dataStart, 0, <usize>array.dataLength);
|
||||
array.length_ = 0; // !
|
||||
var array = NEWARRAY<T>(capacity);
|
||||
array.length_ = 0; // safe even if T is a non-nullable reference
|
||||
memory.fill(array.dataStart, 0, array.dataLength);
|
||||
return array;
|
||||
}
|
||||
|
||||
@ -232,7 +232,9 @@ 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.newArray(thisLen + otherLen, alignof<T>(), __runtime_id<Array<T>>()));
|
||||
var outLen = thisLen + otherLen;
|
||||
if (<u32>outLen > <u32>MAX_BYTELENGTH >>> alignof<T>()) throw new Error(E_INVALIDLENGTH);
|
||||
var out = NEWARRAY<T>(outLen);
|
||||
var outStart = out.dataStart;
|
||||
var thisSize = <usize>thisLen << alignof<T>();
|
||||
if (isManaged<T>()) {
|
||||
@ -320,7 +322,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.newArray(length, alignof<U>(), __runtime_id<Array<U>>()));
|
||||
var out = NEWARRAY<U>(length);
|
||||
var outStart = out.dataStart;
|
||||
for (let index = 0; index < min(length, this.length_); ++index) {
|
||||
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
|
||||
@ -346,7 +348,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.newArray(0, alignof<T>(), __runtime_id<Array<T>>()));
|
||||
var result = NEWARRAY<T>(0);
|
||||
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);
|
||||
@ -434,7 +436,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.newArray(length, alignof<T>(), __runtime_id<Array<T>>()));
|
||||
var slice = NEWARRAY<T>(length);
|
||||
var sliceBase = slice.dataStart;
|
||||
var thisBase = this.dataStart + (<usize>begin << alignof<T>());
|
||||
if (isManaged<T>()) {
|
||||
@ -466,7 +468,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.newArray(deleteCount, alignof<T>(), __runtime_id<Array<T>>()));
|
||||
var result = NEWARRAY<T>(deleteCount);
|
||||
var resultStart = result.dataStart;
|
||||
var thisStart = this.dataStart;
|
||||
var thisBase = thisStart + (<usize>start << alignof<T>());
|
||||
|
@ -1715,3 +1715,36 @@ export namespace v8x16 {
|
||||
l8: u8, l9: u8, l10: u8, l11: u8, l12: u8, l13: u8, l14: u8, l15: u8
|
||||
): v128;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function ERROR(message?: string): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function WARNING(message?: string): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function INFO(message?: string): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@external("env", "abort")
|
||||
declare function abort(
|
||||
message?: string | null,
|
||||
fileName?: string | null,
|
||||
lineNumber?: u32,
|
||||
columnNumber?: u32
|
||||
): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@external("env", "trace")
|
||||
declare function trace(
|
||||
message: string,
|
||||
n?: i32,
|
||||
a0?: f64,
|
||||
a1?: f64,
|
||||
a2?: f64,
|
||||
a3?: f64,
|
||||
a4?: f64
|
||||
): void;
|
||||
|
1
std/assembly/common/README.md
Normal file
1
std/assembly/common/README.md
Normal file
@ -0,0 +1 @@
|
||||
These source files are used by both the standard library *and* compiler. Must remain portable.
|
9
std/assembly/common/capability.ts
Normal file
9
std/assembly/common/capability.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/** Indicates module capabilities. */
|
||||
export const enum Capability {
|
||||
/** No specific capabilities. */
|
||||
NONE = 0,
|
||||
/** Uses WebAssembly with 64-bit pointers. */
|
||||
WASM64 = 1 << 0,
|
||||
/** Garbage collector is present (full runtime header). */
|
||||
GC = 1 << 1
|
||||
}
|
15
std/assembly/common/feature.ts
Normal file
15
std/assembly/common/feature.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/** Indicates specific features to activate. */
|
||||
export const enum Feature {
|
||||
/** No additional features. */
|
||||
NONE = 0,
|
||||
/** Sign extension operations. */
|
||||
SIGN_EXTENSION = 1 << 0, // see: https://github.com/WebAssembly/sign-extension-ops
|
||||
/** Mutable global imports and exports. */
|
||||
MUTABLE_GLOBAL = 1 << 1, // see: https://github.com/WebAssembly/mutable-global
|
||||
/** Bulk memory operations. */
|
||||
BULK_MEMORY = 1 << 2, // see: https://github.com/WebAssembly/bulk-memory-operations
|
||||
/** SIMD types and operations. */
|
||||
SIMD = 1 << 3, // see: https://github.com/WebAssembly/simd
|
||||
/** Threading and atomic operations. */
|
||||
THREADS = 1 << 4 // see: https://github.com/WebAssembly/threads
|
||||
}
|
60
std/assembly/common/rtti.ts
Normal file
60
std/assembly/common/rtti.ts
Normal file
@ -0,0 +1,60 @@
|
||||
// ╒═════════════════════ RTTI interpretation ═════════════════════╕
|
||||
// 3 2 1
|
||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
|
||||
// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤ ◄─ RTTI_BASE
|
||||
// │ count │
|
||||
// ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤
|
||||
// │ reserved │
|
||||
// ╞═══════════════════════════════════════════════════════════════╡ ┐
|
||||
// │ RTTIData#flags [id=1] │ id=1..count
|
||||
// ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤
|
||||
// │ RTTIData#base [id=1] │
|
||||
// ├───────────────────────────────────────────────────────────────┤
|
||||
// │ ... │
|
||||
|
||||
/** Runtime type information data structure. */
|
||||
@unmanaged
|
||||
export class RTTIData {
|
||||
flags: RTTIFlags;
|
||||
base: u32;
|
||||
}
|
||||
|
||||
/** Runtime type information flags. */
|
||||
export const enum RTTIFlags {
|
||||
/** No specific flags. */
|
||||
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
|
||||
}
|
9
std/assembly/common/target.ts
Normal file
9
std/assembly/common/target.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/** Compilation target. */
|
||||
export enum Target {
|
||||
/** WebAssembly with 32-bit pointers. */
|
||||
WASM32,
|
||||
/** WebAssembly with 64-bit pointers. Experimental and not supported by any runtime yet. */
|
||||
WASM64,
|
||||
/** Portable. */
|
||||
JS
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function ERROR(message?: string): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function WARNING(message?: string): void;
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare function INFO(message?: string): void;
|
@ -1,16 +0,0 @@
|
||||
declare function abort(
|
||||
message?: string | null,
|
||||
fileName?: string | null,
|
||||
lineNumber?: u32,
|
||||
columnNumber?: u32
|
||||
): void;
|
||||
|
||||
declare function trace(
|
||||
message: string,
|
||||
n?: i32,
|
||||
a0?: f64,
|
||||
a1?: f64,
|
||||
a2?: f64,
|
||||
a3?: f64,
|
||||
a4?: f64
|
||||
): void;
|
10
std/assembly/index.d.ts
vendored
10
std/assembly/index.d.ts
vendored
@ -1485,13 +1485,6 @@ interface TypedPropertyDescriptor<T> {
|
||||
set?(value: T): void;
|
||||
}
|
||||
|
||||
/** Annotates an element as a program global. */
|
||||
declare function global(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
descriptor: TypedPropertyDescriptor<any>
|
||||
): TypedPropertyDescriptor<any> | void;
|
||||
|
||||
/** Annotates a method as a binary operator overload for the specified `token`. */
|
||||
declare function operator(token:
|
||||
"[]" | "[]=" | "{}" | "{}=" | "==" | "!=" | ">" | "<" | "<=" | ">=" |
|
||||
@ -1526,6 +1519,9 @@ declare namespace operator {
|
||||
) => TypedPropertyDescriptor<any> | void;
|
||||
}
|
||||
|
||||
/** Annotates an element as a program global. */
|
||||
declare function global(...args: any[]): any;
|
||||
|
||||
/** Annotates a class as being unmanaged with limited capabilities. */
|
||||
declare function unmanaged(constructor: Function): void;
|
||||
|
||||
|
@ -3,63 +3,18 @@
|
||||
|
||||
import { HEADER, HEADER_SIZE, allocate, register } from "./util/runtime";
|
||||
import { E_NOTIMPLEMENTED } from "./util/error";
|
||||
import { memory } from "./memory";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
import { RTTIFlags, RTTIData } from "./common/rtti";
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@builtin
|
||||
export declare const RTTI_BASE: usize;
|
||||
|
||||
/** Gets the computed unique id of a class type. */
|
||||
// @ts-ignore: decorator
|
||||
@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
|
||||
@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
|
||||
@ -76,20 +31,24 @@ export class runtime {
|
||||
private constructor() { return unreachable(); }
|
||||
|
||||
/** Determines whether a managed object is considered to be an instance of the class represented by the specified runtime id. */
|
||||
@unsafe
|
||||
static instanceof(ref: usize, id: u32): bool { // keyword
|
||||
return ref
|
||||
? __runtime_instanceof(
|
||||
changetype<HEADER>(ref - HEADER_SIZE).classId,
|
||||
id
|
||||
)
|
||||
: false;
|
||||
static instanceof(ref: usize, superId: u32): bool { // keyword
|
||||
var id = changetype<HEADER>(ref - HEADER_SIZE).classId;
|
||||
var ptr = RTTI_BASE;
|
||||
if (id && id <= load<u32>(ptr)) {
|
||||
do if (id == superId) return true;
|
||||
while (id = changetype<RTTIData>(ptr + id * offsetof<RTTIData>()).base);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export namespace runtime {
|
||||
|
||||
export function flags(id: u32): RuntimeFlags {
|
||||
return __runtime_flags(id);
|
||||
/** Gets the runtime flags of the managed type represented by the specified runtime id. */
|
||||
export function flags(id: u32): RTTIFlags {
|
||||
var ptr = RTTI_BASE;
|
||||
return !id || id > load<u32>(ptr)
|
||||
? unreachable()
|
||||
: changetype<RTTIData>(ptr + id * offsetof<RTTIData>()).flags;
|
||||
}
|
||||
|
||||
/** Allocates and registers, but doesn't initialize the data of, a new managed object of the specified kind. */
|
||||
@ -113,57 +72,36 @@ export namespace runtime {
|
||||
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.*/
|
||||
/** Allocates and registers a new `Array` of the specified kind using the given backing buffer.*/
|
||||
// @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 = register(allocate(offsetof<i32[]>()), id);
|
||||
var bufferSize = <usize>length << alignLog2;
|
||||
var buffer = register(allocate(bufferSize), __runtime_id<ArrayBuffer>());
|
||||
export function newArray(id: u32, buffer: usize): usize {
|
||||
var flags = runtime.flags(id); // traps if invalid
|
||||
var alignLog2 = (<u32>flags / RTTIFlags.VALUE_ALIGN_0) & 31;
|
||||
var byteLength: i32;
|
||||
if (!buffer) buffer = newArrayBuffer(byteLength = 0);
|
||||
else byteLength = changetype<ArrayBuffer>(buffer).byteLength;
|
||||
var array = newObject(id, offsetof<i32[]>());
|
||||
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, bufferSize);
|
||||
// TODO: a way to determine whether the array has managed elements that must be linked?
|
||||
changetype<ArrayBufferView>(array).dataLength = byteLength;
|
||||
store<i32>(changetype<usize>(array), byteLength >>> alignLog2, offsetof<i32[]>("length_"));
|
||||
if (flags & RTTIFlags.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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -1 +1,3 @@
|
||||
import "allocator/arena";
|
||||
|
||||
export { runtime as $ };
|
||||
|
@ -1,10 +1,10 @@
|
||||
/// <reference path="./collector/index.d.ts" />
|
||||
|
||||
import { MAX_SIZE_32 } from "./util/allocator";
|
||||
import { HEADER, HEADER_SIZE, allocate, register } from "./util/runtime";
|
||||
import { HEADER, HEADER_SIZE, allocate, register, NEWARRAY } from "./util/runtime";
|
||||
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||
import { E_INVALIDLENGTH } from "./util/error";
|
||||
import { runtime, __runtime_id } from "./runtime";
|
||||
import { __runtime_id } from "./runtime";
|
||||
import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
@sealed export abstract class String {
|
||||
@ -362,16 +362,16 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
|
||||
split(separator: String | null = null, limit: i32 = i32.MAX_VALUE): String[] {
|
||||
assert(this !== null);
|
||||
if (!limit) return changetype<String[]>(runtime.newArray(0, alignof<String>(), __runtime_id<String[]>()));
|
||||
if (!limit) return NEWARRAY<String>(0);
|
||||
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.newArray(0, alignof<String>(), __runtime_id<String>()));
|
||||
if (!length) return NEWARRAY<String>(0);
|
||||
// split by chars
|
||||
length = min<isize>(length, <isize>limit);
|
||||
let result = changetype<String[]>(runtime.newArray(length, alignof<String>(), __runtime_id<String[]>()));
|
||||
let result = NEWARRAY<String>(length);
|
||||
let resultStart = changetype<ArrayBufferView>(result).dataStart;
|
||||
for (let i: isize = 0; i < length; ++i) {
|
||||
let charStr = allocate(2);
|
||||
@ -385,11 +385,11 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
}
|
||||
return result;
|
||||
} else if (!length) {
|
||||
let result = changetype<String[]>(runtime.newArray(1, alignof<String>(), __runtime_id<String[]>()));
|
||||
let result = NEWARRAY<String>(1);
|
||||
store<string>(changetype<ArrayBufferView>(result).dataStart, ""); // no need to register/link
|
||||
return result;
|
||||
}
|
||||
var result = changetype<String[]>(runtime.newArray(0, alignof<String>(), __runtime_id<String[]>()));
|
||||
var result = NEWARRAY<String>(0);
|
||||
var end = 0, start = 0, i = 0;
|
||||
while ((end = this.indexOf(separator!, start)) != -1) {
|
||||
let len = end - start;
|
||||
@ -404,7 +404,7 @@ import { ArrayBufferView } from "./arraybuffer";
|
||||
start = end + sepLen;
|
||||
}
|
||||
if (!start) {
|
||||
let result = changetype<String[]>(runtime.newArray(1, alignof<String>(), __runtime_id<String[]>()));
|
||||
let result = NEWARRAY<String>(1);
|
||||
unchecked(result[0] = this);
|
||||
return result;
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { AL_MASK, MAX_SIZE_32 } from "./allocator";
|
||||
import { __runtime_id } from "../runtime";
|
||||
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
|
||||
@ -136,22 +139,22 @@ export function register(ref: usize, id: u32): usize {
|
||||
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);
|
||||
export function makeArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {
|
||||
var array = register(allocate(offsetof<i32[]>()), id);
|
||||
var bufferSize = <usize>length << alignLog2;
|
||||
var buffer = register(allocate(bufferSize), __runtime_id<ArrayBuffer>());
|
||||
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);
|
||||
if (data) memory.copy(buffer, data, bufferSize);
|
||||
return array;
|
||||
}
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@inline
|
||||
export function NEWARRAY<T>(length: i32): Array<T> {
|
||||
return changetype<Array<T>>(makeArray(length, alignof<T>(), __runtime_id<Array<T>>(), 0));
|
||||
}
|
||||
|
Reference in New Issue
Block a user