optimize array literal init, warn on unsupported inlining

This commit is contained in:
dcode
2019-03-19 08:20:10 +01:00
parent 83566a5512
commit 7693b543f4
67 changed files with 1808 additions and 5124 deletions

View File

@ -72,8 +72,11 @@ export class Array<T> extends ArrayBufferView {
@operator("[]=") // unchecked is built-in
private __set(index: i32, value: T): void {
ensureCapacity(this, index + 1, alignof<T>());
store<T>(this.dataStart + (<usize>index << alignof<T>()), value);
if (isManaged<T>()) LINK(value, this);
store<T>(this.dataStart + (<usize>index << alignof<T>()),
isManaged<T>()
? LINK<T,this>(value, this)
: value
);
if (index >= this.length_) this.length_ = index + 1;
}
@ -131,8 +134,11 @@ export class Array<T> extends ArrayBufferView {
var newLength = this.length_ + 1;
ensureCapacity(this, newLength, alignof<T>());
this.length_ = newLength;
store<T>(this.dataStart + (<usize>(newLength - 1) << alignof<T>()), element);
if (isManaged<T>()) LINK(element, this);
store<T>(this.dataStart + (<usize>(newLength - 1) << alignof<T>()),
isManaged<T>()
? LINK<T,this>(element, this)
: element
);
return newLength;
}
@ -146,15 +152,13 @@ export class Array<T> extends ArrayBufferView {
let thisStart = this.dataStart;
for (let offset: usize = 0; offset < thisSize; offset += sizeof<T>()) {
let element = load<T>(thisStart + offset);
store<T>(outStart + offset, element);
LINK(element, out);
store<T>(outStart + offset, LINK<T,Array<T>>(element, out));
}
let otherStart = other.dataStart;
let otherSize = <usize>otherLen << alignof<T>();
for (let offset: usize = 0; offset < otherSize; offset += sizeof<T>()) {
let element = load<T>(otherStart + offset);
store<T>(outStart + thisSize + offset, element);
LINK(element, out);
store<T>(outStart + thisSize + offset, LINK<T,Array<T>>(element, out));
}
} else {
memory.copy(outStart, this.dataStart, thisSize);
@ -211,8 +215,11 @@ export class Array<T> extends ArrayBufferView {
for (let index = 0; index < min(length, this.length_); ++index) {
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
let result = callbackfn(value, index, this);
store<U>(outStart + (<usize>index << alignof<U>()), result);
if (isManaged<U>()) LINK(result, out);
store<U>(outStart + (<usize>index << alignof<U>()),
isManaged<U>()
? LINK<U,Array<U>>(result, out)
: result
);
}
return out;
}
@ -283,8 +290,11 @@ export class Array<T> extends ArrayBufferView {
base,
<usize>(newLength - 1) << alignof<T>()
);
store<T>(base, element);
if (isManaged<T>()) LINK(element, this);
store<T>(base,
isManaged<T>()
? LINK<T,this>(element, this)
: element
);
this.length_ = newLength;
return newLength;
}
@ -300,8 +310,11 @@ export class Array<T> extends ArrayBufferView {
for (let i = 0; i < length; ++i) {
let offset = <usize>i << alignof<T>();
let element = load<T>(thisBase + offset);
store<T>(sliceBase + offset, element);
if (isManaged<T>()) LINK(element, slice);
store<T>(sliceBase + offset,
isManaged<T>()
? LINK<T,Array<T>>(element, slice)
: element
);
}
return slice;
}
@ -316,8 +329,11 @@ export class Array<T> extends ArrayBufferView {
var thisBase = thisStart + (<usize>start << alignof<T>());
for (let i = 0; i < deleteCount; ++i) {
let element = load<T>(thisBase + (<usize>i << alignof<T>()));
store<T>(spliceStart + (<usize>i << alignof<T>()), element);
if (isManaged<T>()) LINK(element, splice);
store<T>(spliceStart + (<usize>i << alignof<T>()),
isManaged<T>()
? LINK<T,Array<T>>(element, splice)
: element
);
}
memory.copy(
splice.dataStart,

View File

@ -2,7 +2,7 @@ import { ALLOCATE, REGISTER, HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./runti
@sealed export class ArrayBuffer {
@inline static isView<T>(value: T): bool {
static isView<T>(value: T): bool {
if (value) {
if (value instanceof Int8Array) return true;
if (value instanceof Uint8Array) return true;

View File

@ -58,14 +58,17 @@ export declare function isConstant(expression: void): bool;
@builtin
export declare function isManaged<T>(value?: T): bool;
// @ts-ignore: decorator
@inline
export function isNaN<T>(value: T): bool { return value != value; }
export function isNaN<T extends number>(value: T): bool {
if (!isFloat<T>()) {
if (!isInteger<T>()) ERROR("numeric type expected");
}
return value != value;
}
// @ts-ignore: decorator
@inline
export function isFinite<T>(value: T): bool {
// @ts-ignore: type
export function isFinite<T extends number>(value: T): bool {
if (!isFloat<T>()) {
if (!isInteger<T>()) ERROR("numeric type expected");
}
return value - value == 0;
}

View File

@ -119,15 +119,18 @@ export class Map<K,V> {
entry = changetype<MapEntry<K,V>>(
changetype<usize>(entries) + this.entriesOffset++ * ENTRY_SIZE<K,V>()
);
entry.key = key;
entry.value = value;
// link with the map (entry is unmanaged)
entry.key = isManaged<K>()
? LINK<K,this>(key, this)
: key;
entry.value = isManaged<V>()
? LINK<V,this>(value, this)
: value;
++this.entriesCount;
// link with previous entry in bucket
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
entry.taggedNext = load<usize>(bucketPtrBase);
store<usize>(bucketPtrBase, changetype<usize>(entry));
if (isManaged<K>()) LINK(key, this);
if (isManaged<V>()) LINK(value, this);
}
}

View File

@ -137,10 +137,11 @@ function doRegister(ref: usize, classId: u32): usize {
/** Links a registered object with the (registered) object now referencing it. */
// @ts-ignore: decorator
@unsafe @inline
export function LINK<T,TParent>(ref: T, parentRef: TParent): void {
if (!isReference<T>()) ERROR("reference expected");
if (!isReference<TParent>()) ERROR("reference expected");
export function LINK<T,TParent>(ref: T, parentRef: TParent): T {
if (!isManaged<T>()) ERROR("managed reference expected");
if (!isManaged<TParent>()) ERROR("managed reference expected");
doLink(changetype<usize>(ref), changetype<usize>(parentRef));
return ref;
}
function doLink(ref: usize, parentRef: usize): void {

View File

@ -88,11 +88,11 @@ export class Set<K> {
}
has(key: K): bool {
return this.find(key, HASH(key)) !== null;
return this.find(key, HASH<K>(key)) !== null;
}
add(key: K): void {
var hashCode = HASH(key);
var hashCode = HASH<K>(key);
var entry = this.find(key, hashCode);
if (!entry) {
// check if rehashing is necessary
@ -108,13 +108,15 @@ export class Set<K> {
entry = changetype<SetEntry<K>>(
changetype<usize>(entries) + this.entriesOffset++ * ENTRY_SIZE<K>()
);
entry.key = key;
// link with the set itself (entry is unmanaged)
entry.key = isManaged<K>()
? LINK<K,this>(key, this)
: key;
++this.entriesCount;
// link with previous entry in bucket
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
entry.taggedNext = load<usize>(bucketPtrBase);
store<usize>(bucketPtrBase, changetype<usize>(entry));
if (isManaged<K>()) LINK(key, this);
}
}

View File

@ -362,8 +362,12 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
charStr,
load<u16>(changetype<usize>(this) + (<usize>i << 1))
);
store<usize>(resultStart + (<usize>i << alignof<usize>()), REGISTER<String>(charStr)); // result[i] = charStr
if (isManaged<String>()) LINK(changetype<String>(charStr), result);
// result[i] = charStr
store<String>(resultStart + (<usize>i << alignof<usize>()),
isManaged<String>()
? LINK<String,Array<String>>(REGISTER<String>(charStr), result)
: REGISTER<String>(charStr)
);
}
return result;
} else if (!length) {

View File

@ -620,8 +620,8 @@ export function dtoa_core(buffer: usize, value: f64): i32 {
export function dtoa(value: f64): String {
if (value == 0) return "0.0";
if (!isFinite(value)) {
if (isNaN(value)) return "NaN";
if (!isFinite<f64>(value)) {
if (isNaN<f64>(value)) return "NaN";
return select<String>("-Infinity", "Infinity", value < 0);
}
var temp = ALLOCATE(MAX_DOUBLE_LENGTH << 1);
@ -681,8 +681,8 @@ export function dtoa_stream(buffer: usize, offset: usize, value: f64): u32 {
store<u16>(buffer, CharCode._0, 4);
return 3;
}
if (!isFinite(value)) {
if (isNaN(value)) {
if (!isFinite<f64>(value)) {
if (isNaN<f64>(value)) {
store<u16>(buffer, CharCode.N);
store<u16>(buffer, CharCode.a, 2);
store<u16>(buffer, CharCode.N, 4);