From 42ddc99b790748c8494ee78af71728ccdbc8ee39 Mon Sep 17 00:00:00 2001 From: dcode Date: Thu, 27 Feb 2020 02:54:01 +0100 Subject: [PATCH 01/28] Warn on usize mismatch between 32/64 bits --- src/builtins.ts | 95 ++++++++++----------- src/compiler.ts | 8 ++ src/types.ts | 1 + std/assembly/map.ts | 2 +- std/assembly/rt/common.ts | 2 +- std/assembly/rt/stub.ts | 6 +- std/assembly/rt/tlsf.ts | 22 ++--- std/assembly/set.ts | 2 +- std/assembly/string.ts | 8 +- std/assembly/symbol.ts | 2 +- std/assembly/typedarray.ts | 24 +++--- std/assembly/util/memory.ts | 2 +- std/assembly/util/sort.ts | 14 +-- tests/compiler/memcpy.ts | 2 +- tests/compiler/std/array.optimized.wat | 30 +++---- tests/compiler/std/array.untouched.wat | 56 ++++++------ tests/compiler/std/typedarray.optimized.wat | 10 +-- tests/compiler/std/typedarray.untouched.wat | 14 +-- 18 files changed, 153 insertions(+), 147 deletions(-) diff --git a/src/builtins.ts b/src/builtins.ts index 2684afe098..b6debcf5a7 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -730,7 +730,7 @@ export function compileCall( } return module.i32(signatureReference.parameterTypes.length); } - case BuiltinNames.sizeof: { // sizeof() -> usize + case BuiltinNames.sizeof: { // sizeof() -> usize* compiler.currentType = compiler.options.usizeType; if ( checkTypeRequired(typeArguments, reportNode, compiler) | @@ -745,23 +745,9 @@ export function compileCall( ); return module.unreachable(); } - if (compiler.options.isWasm64) { - // implicitly wrap if contextual type is a 32-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - return module.i32(byteSize); - } - return module.i64(byteSize, 0); - } else { - // implicitly extend if contextual type is a 64-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - return module.i64(byteSize, 0); - } - return module.i32(byteSize); - } + return contextualUsize(compiler, i64_new(byteSize), contextualType); } - case BuiltinNames.alignof: { // alignof() -> usize + case BuiltinNames.alignof: { // alignof() -> usize* compiler.currentType = compiler.options.usizeType; if ( checkTypeRequired(typeArguments, reportNode, compiler) | @@ -776,24 +762,9 @@ export function compileCall( ); return module.unreachable(); } - let alignLog2 = ctz(byteSize); - if (compiler.options.isWasm64) { - // implicitly wrap if contextual type is a 32-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - return module.i32(alignLog2); - } - return module.i64(alignLog2, 0); - } else { - // implicitly extend if contextual type is a 64-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - return module.i64(alignLog2, 0); - } - return module.i32(alignLog2); - } + return contextualUsize(compiler, i64_new(ctz(byteSize)), contextualType); } - case BuiltinNames.offsetof: { // offsetof(fieldName?: string) -> usize + case BuiltinNames.offsetof: { // offsetof(fieldName?: string) -> usize* compiler.currentType = compiler.options.usizeType; if ( checkTypeRequired(typeArguments, reportNode, compiler) | @@ -842,21 +813,7 @@ export function compileCall( } else { offset = classType.nextMemoryOffset; } - if (compiler.options.isWasm64) { - // implicitly wrap if contextual type is a 32-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - return module.i32(offset); - } - return module.i64(offset); - } else { - // implicitly extend if contextual type is a 64-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - return module.i64(offset); - } - return module.i32(offset); - } + return contextualUsize(compiler, i64_new(offset), contextualType); } case BuiltinNames.nameof: { let resultType = evaluateConstantType(compiler, typeArguments, operands, reportNode); @@ -5225,3 +5182,43 @@ function checkArgsOptional( } return 0; } + +/** Makes an usize constant matching contextual type if reasonable. */ +function contextualUsize(compiler: Compiler, value: I64, contextualType: Type): ExpressionRef { + var module = compiler.module; + // Check if contextual type fits + if (contextualType != Type.auto && contextualType.is(TypeFlags.INTEGER | TypeFlags.VALUE)) { + switch (contextualType.kind) { + case TypeKind.I32: { + if (i64_is_i32(value)) { + compiler.currentType = Type.i32; + return module.i32(i64_low(value)); + } + break; + } + case TypeKind.U32: { + if (i64_is_u32(value)) { + compiler.currentType = Type.u32; + return module.i32(i64_low(value)); + } + break; + } + case TypeKind.I64: + case TypeKind.U64: { + compiler.currentType = contextualType; + return module.i64(i64_low(value), i64_high(value)); + } + // isize/usize falls through + // small int is probably not intended + } + } + // Default to usize + if (compiler.options.isWasm64) { + compiler.currentType = Type.usize64; + return module.i64(i64_low(value), i64_high(value)); + } else { + compiler.currentType = Type.usize32; + assert(!i64_high(value)); + return module.i32(i64_low(value)); + } +} diff --git a/src/compiler.ts b/src/compiler.ts index 238527644a..0f3b309193 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -3456,6 +3456,14 @@ export class Compiler extends DiagnosticEmitter { expr = this.ensureSmallIntegerWrap(expr, fromType); // must clear garbage bits wrap = false; } + // same size + } else { + if (!explicit && !this.options.isWasm64 && fromType.is(TypeFlags.POINTER) && !toType.is(TypeFlags.POINTER)) { + this.warning( + DiagnosticCode.Conversion_from_type_0_to_1_will_require_an_explicit_cast_when_switching_between_32_64_bit, + reportNode.range, fromType.toString(), toType.toString() + ); + } } } } diff --git a/src/types.ts b/src/types.ts index a200cae828..96ae9b9a14 100644 --- a/src/types.ts +++ b/src/types.ts @@ -133,6 +133,7 @@ export class Type { /** Returns the closest int type representing this type. */ get intType(): Type { + if (this == Type.auto) return this; // keep auto as a hint switch (this.kind) { case TypeKind.I8: return Type.i8; case TypeKind.I16: return Type.i16; diff --git a/std/assembly/map.ts b/std/assembly/map.ts index 51fdf243af..0e82f9f96c 100644 --- a/std/assembly/map.ts +++ b/std/assembly/map.ts @@ -137,7 +137,7 @@ export class Map { } // append new entry let entries = this.entries; - entry = changetype>(changetype(entries) + this.entriesOffset++ * ENTRY_SIZE()); + entry = changetype>(changetype(entries) + (this.entriesOffset++) * ENTRY_SIZE()); // link with the map entry.key = isManaged() ? changetype(__retain(changetype(key))) diff --git a/std/assembly/rt/common.ts b/std/assembly/rt/common.ts index 0c046c770f..58ffd86eed 100644 --- a/std/assembly/rt/common.ts +++ b/std/assembly/rt/common.ts @@ -37,7 +37,7 @@ } // @ts-ignore: decorator -@inline export const BLOCK_OVERHEAD = (offsetof() + AL_MASK) & ~AL_MASK; +@inline export const BLOCK_OVERHEAD: usize = (offsetof() + AL_MASK) & ~AL_MASK; // @ts-ignore: decorator @inline export const BLOCK_MAXSIZE: usize = (1 << 30) - BLOCK_OVERHEAD; diff --git a/std/assembly/rt/stub.ts b/std/assembly/rt/stub.ts index 04867d60f3..53ad191389 100644 --- a/std/assembly/rt/stub.ts +++ b/std/assembly/rt/stub.ts @@ -13,7 +13,7 @@ function maybeGrowMemory(newOffset: usize): void { var pagesBefore = memory.size(); var maxOffset = pagesBefore << 16; if (newOffset > maxOffset) { - let pagesNeeded = ((newOffset - maxOffset + 0xffff) & ~0xffff) >>> 16; + let pagesNeeded = (((newOffset - maxOffset + 0xffff) & ~0xffff) >>> 16); let pagesWanted = max(pagesBefore, pagesNeeded); // double memory if (memory.grow(pagesWanted) < 0) { if (memory.grow(pagesNeeded) < 0) unreachable(); // out of memory @@ -33,7 +33,7 @@ export function __alloc(size: usize, id: u32): usize { block.mmInfo = actualSize; if (DEBUG) block.gcInfo = 1; block.rtId = id; - block.rtSize = size; + block.rtSize = size; return ptr; } @@ -60,7 +60,7 @@ export function __realloc(ptr: usize, size: usize): usize { offset = ptr + alignedSize; block.mmInfo = alignedSize; } - block.rtSize = size; + block.rtSize = size; return ptr; } diff --git a/std/assembly/rt/tlsf.ts b/std/assembly/rt/tlsf.ts index c797f21794..486e860de7 100644 --- a/std/assembly/rt/tlsf.ts +++ b/std/assembly/rt/tlsf.ts @@ -19,12 +19,12 @@ import { REFCOUNT_MASK } from "./pure"; // @ts-ignore: decorator @inline const SL_BITS: u32 = 4; // @ts-ignore: decorator -@inline const SL_SIZE: usize = 1 << SL_BITS; +@inline const SL_SIZE: u32 = 1 << SL_BITS; // @ts-ignore: decorator -@inline const SB_BITS: usize = (SL_BITS + AL_BITS); +@inline const SB_BITS: u32 = SL_BITS + AL_BITS; // @ts-ignore: decorator -@inline const SB_SIZE: usize = 1 << SB_BITS; +@inline const SB_SIZE: u32 = 1 << SB_BITS; // @ts-ignore: decorator @inline const FL_BITS: u32 = 31 - SB_BITS; @@ -130,15 +130,15 @@ import { REFCOUNT_MASK } from "./pure"; // Root constants. Where stuff is stored inside of the root structure. // @ts-ignore: decorator -@inline const SL_START = sizeof(); +@inline const SL_START: usize = sizeof(); // @ts-ignore: decorator -@inline const SL_END = SL_START + (FL_BITS << alignof()); +@inline const SL_END: usize = SL_START + (FL_BITS << alignof()); // @ts-ignore: decorator -@inline const HL_START = (SL_END + AL_MASK) & ~AL_MASK; +@inline const HL_START: usize = (SL_END + AL_MASK) & ~AL_MASK; // @ts-ignore: decorator -@inline const HL_END = HL_START + FL_BITS * SL_SIZE * sizeof(); +@inline const HL_END: usize = HL_START + FL_BITS * SL_SIZE * sizeof(); // @ts-ignore: decorator -@inline const ROOT_SIZE = HL_END + sizeof(); +@inline const ROOT_SIZE: usize = HL_END + sizeof(); // @ts-ignore: decorator @lazy export var ROOT: Root; @@ -510,7 +510,7 @@ export function allocateBlock(root: Root, size: usize, id: u32): Block { if (DEBUG) assert((block.mmInfo & ~TAGS_MASK) >= payloadSize); // must fit block.gcInfo = 0; // RC=0 block.rtId = id; - block.rtSize = size; + block.rtSize = size; removeBlock(root, block); prepareBlock(root, block, payloadSize); if (isDefined(ASC_RTRACE)) onalloc(block); @@ -525,7 +525,7 @@ export function reallocateBlock(root: Root, block: Block, size: usize): Block { // possibly split and update runtime size if it still fits if (payloadSize <= (blockInfo & ~TAGS_MASK)) { prepareBlock(root, block, payloadSize); - block.rtSize = size; + block.rtSize = size; return block; } @@ -539,7 +539,7 @@ export function reallocateBlock(root: Root, block: Block, size: usize): Block { // TODO: this can yield an intermediate block larger than BLOCK_MAXSIZE, which // is immediately split though. does this trigger any assertions / issues? block.mmInfo = (blockInfo & TAGS_MASK) | mergeSize; - block.rtSize = size; + block.rtSize = size; prepareBlock(root, block, payloadSize); return block; } diff --git a/std/assembly/set.ts b/std/assembly/set.ts index 76a7b66ed3..ca2a1ca299 100644 --- a/std/assembly/set.ts +++ b/std/assembly/set.ts @@ -114,7 +114,7 @@ export class Set { ); } // append new entry - entry = changetype>(changetype(this.entries) + this.entriesOffset++ * ENTRY_SIZE()); + entry = changetype>(changetype(this.entries) + (this.entriesOffset++) * ENTRY_SIZE()); entry.key = isManaged() ? changetype(__retain(changetype(key))) : key; diff --git a/std/assembly/string.ts b/std/assembly/string.ts index e4e88da4d9..b2065c8de5 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -8,7 +8,7 @@ import { idof } from "./builtins"; @sealed export abstract class String { - @lazy static readonly MAX_LENGTH: i32 = BLOCK_MAXSIZE >>> alignof(); + @lazy static readonly MAX_LENGTH: i32 = (BLOCK_MAXSIZE >>> alignof()); static fromCharCode(unit: i32, surr: i32 = -1): String { var hasSur = surr > 0; @@ -446,13 +446,13 @@ import { idof } from "./builtins"; if (!limit) return changetype>(__allocArray(0, alignof(), idof>())); // retains if (separator === null) return [this]; var length: isize = this.length; - var sepLen: isize = separator.length; + var sepLen = separator.length; if (limit < 0) limit = i32.MAX_VALUE; if (!sepLen) { if (!length) return changetype>(__allocArray(0, alignof(), idof>())); // retains // split by chars length = min(length, limit); - let result = changetype>(__allocArray(length, alignof(), idof>())); // retains + let result = changetype>(__allocArray(length, alignof(), idof>())); // retains // @ts-ignore: cast let resultStart = result.dataStart as usize; for (let i: isize = 0; i < length; ++i) { @@ -578,7 +578,7 @@ import { idof } from "./builtins"; // monkey patch store(codes + (j << 1), c - 26); } else { - let index = -1; + let index: usize = -1; // Fast range check. See first and last rows in specialsUpper table if (c - 0x00DF <= 0xFB17 - 0x00DF) { index = bsearch(c, changetype(SPECIALS_UPPER), specialsUpperLen); diff --git a/std/assembly/symbol.ts b/std/assembly/symbol.ts index 97baef4d58..b503b50705 100644 --- a/std/assembly/symbol.ts +++ b/std/assembly/symbol.ts @@ -85,7 +85,7 @@ var nextId: usize = 12; // Symbol.unscopables + 1 toString(): string { var id = changetype(this); var str = ""; - switch (id) { + switch (id) { case 1: { str = "hasInstance"; break; } case 2: { str = "isConcatSpreadable"; break; } case 3: { str = "isRegExp"; break; } diff --git a/std/assembly/typedarray.ts b/std/assembly/typedarray.ts index e96e4c7655..947fbf917c 100644 --- a/std/assembly/typedarray.ts +++ b/std/assembly/typedarray.ts @@ -9,7 +9,7 @@ export class Int8Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -137,7 +137,7 @@ export class Uint8Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -265,7 +265,7 @@ export class Uint8ClampedArray extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -393,7 +393,7 @@ export class Int16Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -521,7 +521,7 @@ export class Uint16Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -649,7 +649,7 @@ export class Int32Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -777,7 +777,7 @@ export class Uint32Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -905,7 +905,7 @@ export class Int64Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1033,7 +1033,7 @@ export class Uint64Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1161,7 +1161,7 @@ export class Float32Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1289,7 +1289,7 @@ export class Float64Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1736,7 +1736,7 @@ function REVERSE(array: TArray): TArray { function WRAP(buffer: ArrayBuffer, byteOffset: i32 = 0, length: i32 = -1): TArray { var byteLength: i32; var bufferByteLength = buffer.byteLength; - const mask = sizeof() - 1; + const mask: u32 = sizeof() - 1; if (i32(byteOffset > bufferByteLength) | (byteOffset & mask)) { throw new RangeError(E_INDEXOUTOFRANGE); } diff --git a/std/assembly/util/memory.ts b/std/assembly/util/memory.ts index 26d42b883b..e960254e8f 100644 --- a/std/assembly/util/memory.ts +++ b/std/assembly/util/memory.ts @@ -38,7 +38,7 @@ export function memcpy(dest: usize, src: usize, n: usize): void { // see: musl/s // if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each // doing shifts if faster when copying enough bytes (here: 32 or more) if (n >= 32) { - switch (dest & 3) { + switch (dest & 3) { // known to be != 0 case 1: { w = load(src); diff --git a/std/assembly/util/sort.ts b/std/assembly/util/sort.ts index 0bd18f0a52..3ab895b259 100644 --- a/std/assembly/util/sort.ts +++ b/std/assembly/util/sort.ts @@ -86,7 +86,7 @@ function weakHeapSort( ): void { const shift32 = alignof(); - var bitsetSize = (length + 31) >> 5 << shift32; + var bitsetSize = (length + 31) >> 5 << shift32; var bitset = __alloc(bitsetSize, 0); // indexed in 32-bit chunks below memory.fill(bitset, 0, bitsetSize); @@ -94,15 +94,15 @@ function weakHeapSort( for (let i = length - 1; i > 0; i--) { let j = i; - while ((j & 1) == (load(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1; + while ((j & 1) == (load(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1; let p = j >> 1; let a: T = load(dataStart + (p << alignof())); // a = arr[p] let b: T = load(dataStart + (i << alignof())); // b = arr[i] if (comparator(a, b) < 0) { store( - bitset + (i >> 5 << shift32), - load(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31)) + bitset + (i >> 5 << shift32), + load(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31)) ); store(dataStart + (i << alignof()), a); // arr[i] = a store(dataStart + (p << alignof()), b); // arr[p] = b @@ -115,7 +115,7 @@ function weakHeapSort( store(dataStart + (i << alignof()), a); // arr[i] = a let x = 1, y: i32; - while ((y = (x << 1) + ((load(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y; + while ((y = (x << 1) + ((load(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y; while (x > 0) { a = load(dataStart); // a = arr[0] @@ -123,8 +123,8 @@ function weakHeapSort( if (comparator(a, b) < 0) { store( - bitset + (x >> 5 << shift32), - load(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31)) + bitset + (x >> 5 << shift32), + load(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31)) ); store(dataStart + (x << alignof()), a); // arr[x] = a store(dataStart, b); // arr[0] = b diff --git a/tests/compiler/memcpy.ts b/tests/compiler/memcpy.ts index 88879a3aa0..3c7a13774b 100644 --- a/tests/compiler/memcpy.ts +++ b/tests/compiler/memcpy.ts @@ -39,7 +39,7 @@ export function memcpy(dest: usize, src: usize, n: usize): usize { // if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each // doing shifts if faster when copying enough bytes (here: 32 or more) if (n >= 32) { - switch (dest % 4) { + switch (dest % 4) { // known to be != 0 case 1: w = load(src); diff --git a/tests/compiler/std/array.optimized.wat b/tests/compiler/std/array.optimized.wat index 83a49f35dc..798aea0dba 100644 --- a/tests/compiler/std/array.optimized.wat +++ b/tests/compiler/std/array.optimized.wat @@ -4325,7 +4325,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $2 @@ -4353,7 +4353,7 @@ local.get $5 local.get $2 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4403,7 +4403,7 @@ local.get $5 local.get $3 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4469,7 +4469,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4519,7 +4519,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4816,7 +4816,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $2 @@ -4844,7 +4844,7 @@ local.get $5 local.get $2 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4894,7 +4894,7 @@ local.get $5 local.get $3 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4960,7 +4960,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5010,7 +5010,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5329,7 +5329,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $3 @@ -5357,7 +5357,7 @@ local.get $5 local.get $3 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5408,7 +5408,7 @@ local.get $5 local.get $4 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5474,7 +5474,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5525,7 +5525,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add diff --git a/tests/compiler/std/array.untouched.wat b/tests/compiler/std/array.untouched.wat index a25ffb50b5..b5125b29bf 100644 --- a/tests/compiler/std/array.untouched.wat +++ b/tests/compiler/std/array.untouched.wat @@ -7121,7 +7121,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -7153,7 +7153,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7207,14 +7207,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7286,7 +7286,7 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7338,14 +7338,14 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7734,7 +7734,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -7766,7 +7766,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7820,14 +7820,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7899,7 +7899,7 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7951,14 +7951,14 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8380,7 +8380,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -8412,7 +8412,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8466,14 +8466,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8545,7 +8545,7 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8597,14 +8597,14 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8856,7 +8856,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -8888,7 +8888,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8942,14 +8942,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -9021,7 +9021,7 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -9073,14 +9073,14 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add diff --git a/tests/compiler/std/typedarray.optimized.wat b/tests/compiler/std/typedarray.optimized.wat index 012bd33244..0865f15820 100644 --- a/tests/compiler/std/typedarray.optimized.wat +++ b/tests/compiler/std/typedarray.optimized.wat @@ -2560,7 +2560,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $2 @@ -2588,7 +2588,7 @@ local.get $5 local.get $2 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -2638,7 +2638,7 @@ local.get $5 local.get $3 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -2704,7 +2704,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -2754,7 +2754,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add diff --git a/tests/compiler/std/typedarray.untouched.wat b/tests/compiler/std/typedarray.untouched.wat index 5a9464760c..cc73f6ad8a 100644 --- a/tests/compiler/std/typedarray.untouched.wat +++ b/tests/compiler/std/typedarray.untouched.wat @@ -3231,7 +3231,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -3263,7 +3263,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -3317,14 +3317,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -3396,7 +3396,7 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -3448,14 +3448,14 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add From fbc9144e6bc6c04ff3b97534794edbbb8777fc69 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 28 Feb 2020 00:32:04 +0100 Subject: [PATCH 02/28] Add temporary fillers for Map/Set#keys/values --- src/ast.ts | 32 +++++++- src/builtins.ts | 37 ++++++--- src/compiler.ts | 31 +++++++- src/definitions.ts | 114 ++++++++++++++++++++-------- src/diagnosticMessages.generated.ts | 2 + src/diagnosticMessages.json | 1 + src/extra/ast.ts | 15 ++++ src/flow.ts | 20 +++-- src/glue/binaryen.d.ts | 2 +- src/glue/js/index.ts | 1 + src/glue/js/mapset.d.ts | 3 + src/glue/js/mapset.js | 23 ++++++ src/glue/wasm/index.ts | 1 + src/glue/wasm/mapset.ts | 14 ++++ src/module.ts | 6 +- src/parser.ts | 106 +++++++++++++++++++++++--- src/program.ts | 85 +++++++++++++++------ src/resolver.ts | 27 ++++--- src/util/collections.ts | 24 ++++-- tests/parser/forof.ts | 16 ++++ tests/parser/forof.ts.fixture.ts | 16 ++++ 21 files changed, 469 insertions(+), 107 deletions(-) create mode 100644 src/glue/js/mapset.d.ts create mode 100644 src/glue/js/mapset.js create mode 100644 src/glue/wasm/mapset.ts create mode 100644 tests/parser/forof.ts create mode 100644 tests/parser/forof.ts.fixture.ts diff --git a/src/ast.ts b/src/ast.ts index 009c756f58..bc6c8958a8 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -70,6 +70,7 @@ export enum NodeKind { EXPORTIMPORT, EXPRESSION, FOR, + FOROF, IF, IMPORT, RETURN, @@ -835,6 +836,20 @@ export abstract class Node { return stmt; } + static createForOfStatement( + variable: Statement, + iterable: Expression, + statement: Statement, + range: Range + ): ForOfStatement { + var stmt = new ForOfStatement(); + stmt.range = range; + stmt.variable = variable; + stmt.iterable = iterable; + stmt.statement = statement; + return stmt; + } + static createFunctionDeclaration( name: IdentifierExpression, typeParameters: TypeParameterNode[] | null, @@ -1844,10 +1859,7 @@ export class FieldDeclaration extends VariableLikeDeclarationStatement { export class ForStatement extends Statement { kind = NodeKind.FOR; - /** - * Initializer statement, if present. - * Either a {@link VariableStatement} or {@link ExpressionStatement}. - */ + /** Initializer statement, if present. Either a `VariableStatement` or `ExpressionStatement`. */ initializer: Statement | null; /** Condition expression, if present. */ condition: Expression | null; @@ -1857,6 +1869,18 @@ export class ForStatement extends Statement { statement: Statement; } +/** Represents a `for..of` statement. */ +export class ForOfStatement extends Statement { + kind = NodeKind.FOROF; + + /** Variable statement. Either a `VariableStatement` or `ExpressionStatement` of `IdentifierExpression`. */ + variable: Statement; + /** Iterable expression being iterated. */ + iterable: Expression; + /** Statement being looped over. */ + statement: Statement; +} + /** Indicates the kind of an array function. */ export const enum ArrowKind { /** Not an arrow function. */ diff --git a/src/builtins.ts b/src/builtins.ts index b6debcf5a7..7622b1440e 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -4695,7 +4695,9 @@ export function compileVisitGlobals(compiler: Compiler): void { // this function is @lazy: make sure it exists compiler.compileFunction(visitInstance, true); - for (let element of compiler.program.elementsByName.values()) { + // for (let element of compiler.program.elementsByName.values()) { + for (let _values = Map_values(compiler.program.elementsByName), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); if (element.kind != ElementKind.GLOBAL) continue; let global = element; let globalType = global.type; @@ -4775,9 +4777,12 @@ export function compileVisitMembers(compiler: Compiler): void { ); var lastId = 0; - for (let [id, instance] of managedClasses) { + // for (let [instanceId, instance] of managedClasses) { + for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { + let instanceId = _keys[i]; + let instance = managedClasses.get(instanceId)!; assert(instance.type.isManaged); - assert(id == lastId++); + assert(instanceId == lastId++); let visitImpl: Element | null; let code = new Array(); @@ -4811,7 +4816,9 @@ export function compileVisitMembers(compiler: Compiler): void { } else { let members = instance.members; if (members) { - for (let member of members.values()) { + // for (let member of members.values()) { + for (let _values = Map_values(members), j = 0, l = _values.length; j < l; ++j) { + let member = unchecked(_values[j]); if (member.kind == ElementKind.FIELD) { if ((member).parent === instance) { let fieldType = (member).type; @@ -4843,14 +4850,15 @@ export function compileVisitMembers(compiler: Compiler): void { let block = relooper.addBlock( module.flatten(code) ); - relooper.addBranchForSwitch(outer, block, [ id ]); + relooper.addBranchForSwitch(outer, block, [ instanceId ]); blocks.push(block); } - for (let [id, instance] of managedClasses) { + // for (let [instanceId, instance] of managedClasses) { + for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { + let instanceId = unchecked(_keys[i]); + let instance = managedClasses.get(instanceId)!; let base = instance.base; - if (base) { - relooper.addBranch(blocks[id], blocks[base.id]); - } + if (base) relooper.addBranch(blocks[instanceId], blocks[base.id]); } blocks.push( relooper.addBlock( @@ -4892,8 +4900,11 @@ export function compileRTTI(compiler: Compiler): void { var setPrototype = program.setPrototype; var mapPrototype = program.mapPrototype; var lastId = 0; - for (let [id, instance] of managedClasses) { - assert(id == lastId++); + // for (let [instanceId, instance] of managedClasses) { + for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { + let instanceId = unchecked(_keys[i]); + let instance = managedClasses.get(instanceId)!; + assert(instanceId == lastId++); let flags: TypeinfoFlags = 0; if (instance.isAcyclic) flags |= TypeinfoFlags.ACYCLIC; if (instance !== abvInstance && instance.extends(abvPrototype)) { @@ -4956,7 +4967,9 @@ export function compileClassInstanceOf(compiler: Compiler, prototype: ClassProto // if (__instanceof(ref, ID[i])) return true var instances = prototype.instances; if (instances !== null && instances.size) { - for (let instance of instances.values()) { + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); stmts.push( module.if( module.call(instanceofInstance.internalName, [ diff --git a/src/compiler.ts b/src/compiler.ts index 0f3b309193..22a2690ac0 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -126,6 +126,7 @@ import { ExpressionStatement, FieldDeclaration, ForStatement, + ForOfStatement, FunctionDeclaration, IfStatement, ImportStatement, @@ -1827,6 +1828,10 @@ export class Compiler extends DiagnosticEmitter { stmt = this.compileForStatement(statement); break; } + case NodeKind.FOROF: { + stmt = this.compileForOfStatement(statement); + break; + } case NodeKind.IF: { stmt = this.compileIfStatement(statement); break; @@ -2328,6 +2333,16 @@ export class Compiler extends DiagnosticEmitter { return module.flatten(stmts); } + private compileForOfStatement( + statement: ForOfStatement + ): ExpressionRef { + this.error( + DiagnosticCode.Not_implemented, + statement.range + ); + return this.module.unreachable(); + } + private compileIfStatement( statement: IfStatement ): ExpressionRef { @@ -6933,7 +6948,9 @@ export class Compiler extends DiagnosticEmitter { var scopedLocals = flow.scopedLocals; if (scopedLocals) { let module = this.module; - for (let local of scopedLocals.values()) { + // for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); if (local.is(CommonFlags.SCOPED)) { // otherwise an alias let localIndex = local.index; if (flow.isAnyLocalFlag(localIndex, LocalFlags.ANY_RETAINED)) { @@ -7005,12 +7022,16 @@ export class Compiler extends DiagnosticEmitter { while (parent = current.parent) current = parent; let scopedLocals = current.scopedLocals; if (scopedLocals) { - for (let local of scopedLocals.values()) { + // for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); this.maybeFinishAutorelease(local, flow, stmts); } } } else { - for (let local of flow.parentFunction.localsByIndex) { + let localsByIndex = flow.parentFunction.localsByIndex; + for (let i = 0, k = localsByIndex.length; i < k; ++i) { + let local = unchecked(localsByIndex[i]); this.maybeFinishAutorelease(local, flow, stmts); } } @@ -9749,7 +9770,9 @@ export class Compiler extends DiagnosticEmitter { : 0; var nativeSizeType = this.options.nativeSizeType; - for (let member of members.values()) { + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if ( member.kind != ElementKind.FIELD || // not a field member.parent != classInstance // inherited field diff --git a/src/definitions.ts b/src/definitions.ts index c9d34d726b..b0527170eb 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -58,20 +58,30 @@ export abstract class ExportsWalker { /** Walks all elements and calls the respective handlers. */ walk(): void { - for (let file of this.program.filesByName.values()) { + // for (let file of this.program.filesByName.values()) { + for (let _values = Map_values(this.program.filesByName), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) this.visitFile(file); } } /** Visits all exported elements of a file. */ visitFile(file: File): void { - var members = file.exports; - if (members) { - for (let [name, member] of members) this.visitElement(name, member); + var exports = file.exports; + if (exports) { + // for (let [memberName, member] of exports) { + for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = exports.get(memberName)!; + this.visitElement(memberName, member); + } } var exportsStar = file.exportsStar; if (exportsStar) { - for (let exportStar of exportsStar) this.visitFile(exportStar); + for (let i = 0, k = exportsStar.length; i < k; ++i) { + let exportStar = unchecked(exportsStar[i]); + this.visitFile(exportStar); + } } } @@ -129,8 +139,10 @@ export abstract class ExportsWalker { private visitFunctionInstances(name: string, element: FunctionPrototype): void { var instances = element.instances; if (instances) { - for (let instance of instances.values()) { - if (instance.is(CommonFlags.COMPILED)) this.visitFunction(name, instance); + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); + if (instance.is(CommonFlags.COMPILED)) this.visitFunction(name, instance); } } } @@ -138,8 +150,10 @@ export abstract class ExportsWalker { private visitClassInstances(name: string, element: ClassPrototype): void { var instances = element.instances; if (instances) { - for (let instance of instances.values()) { - if (instance.is(CommonFlags.COMPILED)) this.visitClass(name, instance); + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); + if (instance.is(CommonFlags.COMPILED)) this.visitClass(name, instance); } } } @@ -214,23 +228,29 @@ export class IDLBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - for (let [name, member] of members) { + // for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = members.get(memberName)!; if (member.kind == ElementKind.ENUMVALUE) { - let isConst = (member).is(CommonFlags.INLINED); + let value = member; + let isConst = value.is(CommonFlags.INLINED); indent(sb, this.indentLevel); if (isConst) sb.push("const "); else sb.push("readonly "); sb.push("unsigned long "); - sb.push(name); + sb.push(memberName); if (isConst) { sb.push(" = "); - assert((member).constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low((member).constantIntegerValue).toString(10)); + assert(value.constantValueKind == ConstantValueKind.INTEGER); + sb.push(i64_low(value.constantIntegerValue).toString(10)); } sb.push(";\n"); } } - for (let member of members.values()) { + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) this.visitElement(member.name, member); } } @@ -258,12 +278,16 @@ export class IDLBuilder extends ExportsWalker { } sb.push(");\n"); var members = element.members; - if (members && members.size) { + if (members !== null && members.size) { indent(sb, this.indentLevel); sb.push("interface "); sb.push(element.name); sb.push(" {\n"); - for (let member of members.values()) this.visitElement(member.name, member); + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } indent(sb, --this.indentLevel); sb.push("}\n"); } @@ -296,7 +320,11 @@ export class IDLBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - for (let member of members.values()) this.visitElement(member.name, member); + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } } indent(sb, --this.indentLevel); sb.push("}\n"); @@ -385,21 +413,25 @@ export class TSDBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - let numMembers = members.size; - for (let [name, member] of members) { + let remainingMembers = members.size; + // for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = members.get(memberName)!; if (member.kind == ElementKind.ENUMVALUE) { + let value = member; indent(sb, this.indentLevel); - sb.push(name); + sb.push(memberName); if (member.is(CommonFlags.INLINED)) { sb.push(" = "); - assert((member).constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low((member).constantIntegerValue).toString(10)); + assert(value.constantValueKind == ConstantValueKind.INTEGER); + sb.push(i64_low(value.constantIntegerValue).toString(10)); } sb.push(",\n"); - --numMembers; + --remainingMembers; } } - if (numMembers) this.visitNamespace(name, element); + if (remainingMembers) this.visitNamespace(name, element); } indent(sb, --this.indentLevel); sb.push("}\n"); @@ -463,11 +495,19 @@ export class TSDBuilder extends ExportsWalker { sb.push(" {\n"); var staticMembers = element.prototype.members; if (staticMembers) { - for (let member of staticMembers.values()) this.visitElement(member.name, member); + // for (let member of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } } var instanceMembers = element.members; if (instanceMembers) { - for (let member of instanceMembers.values()) this.visitElement(member.name, member); + // for (let member of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } } indent(sb, --this.indentLevel); sb.push("}\n"); @@ -492,13 +532,17 @@ export class TSDBuilder extends ExportsWalker { visitNamespace(name: string, element: Element): void { var members = element.members; - if (members && members.size) { + if (members !== null && members.size) { let sb = this.sb; indent(sb, this.indentLevel++); sb.push("export namespace "); sb.push(name); sb.push(" {\n"); - for (let member of members.values()) this.visitElement(member.name, member); + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } indent(sb, --this.indentLevel); sb.push("}\n"); } @@ -567,12 +611,16 @@ export class TSDBuilder extends ExportsWalker { function hasCompiledMember(element: Element): bool { var members = element.members; if (members) { - for (let member of members.values()) { + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); switch (member.kind) { case ElementKind.FUNCTION_PROTOTYPE: { let instances = (member).instances; if (instances) { - for (let instance of instances.values()) { + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), j = 0, l = _values.length; j < l; ++j) { + let instance = unchecked(_values[j]); if (instance.is(CommonFlags.COMPILED)) return true; } } @@ -581,7 +629,9 @@ function hasCompiledMember(element: Element): bool { case ElementKind.CLASS_PROTOTYPE: { let instances = (member).instances; if (instances) { - for (let instance of instances.values()) { + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), j = 0, l = _values.length; j < l; ++j) { + let instance = unchecked(_values[j]); if (instance.is(CommonFlags.COMPILED)) return true; } } diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index 68e21cfa2d..eeb904ee1b 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -93,6 +93,7 @@ export enum DiagnosticCode { Binary_digit_expected = 1177, Octal_digit_expected = 1178, An_implementation_cannot_be_declared_in_ambient_contexts = 1183, + The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer = 1190, An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive = 1198, Unterminated_Unicode_escape_sequence = 1199, Decorators_are_not_valid_here = 1206, @@ -244,6 +245,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 1177: return "Binary digit expected."; case 1178: return "Octal digit expected."; case 1183: return "An implementation cannot be declared in ambient contexts."; + case 1190: return "The variable declaration of a 'for...of' statement cannot have an initializer."; case 1198: return "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive."; case 1199: return "Unterminated Unicode escape sequence."; case 1206: return "Decorators are not valid here."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index 655b26c520..bb71ba653c 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -88,6 +88,7 @@ "Binary digit expected.": 1177, "Octal digit expected.": 1178, "An implementation cannot be declared in ambient contexts.": 1183, + "The variable declaration of a 'for...of' statement cannot have an initializer.": 1190, "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.": 1198, "Unterminated Unicode escape sequence.": 1199, "Decorators are not valid here.": 1206, diff --git a/src/extra/ast.ts b/src/extra/ast.ts index 2b0d711419..946aab1a01 100644 --- a/src/extra/ast.ts +++ b/src/extra/ast.ts @@ -55,6 +55,7 @@ import { ExportDefaultStatement, ExpressionStatement, ForStatement, + ForOfStatement, IfStatement, ImportStatement, InstanceOfExpression, @@ -251,6 +252,10 @@ export class ASTBuilder { this.visitForStatement(node); break; } + case NodeKind.FOROF: { + this.visitForOfStatement(node); + break; + } case NodeKind.IF: { this.visitIfStatement(node); break; @@ -1126,6 +1131,16 @@ export class ASTBuilder { this.visitNode(node.statement); } + visitForOfStatement(node: ForOfStatement): void { + var sb = this.sb; + sb.push("for ("); + this.visitNode(node.variable); + sb.push(" of "); + this.visitNode(node.iterable); + sb.push(") "); + this.visitNode(node.statement); + } + visitFunctionDeclaration(node: FunctionDeclaration, isDefault: bool = false): void { var sb = this.sb; var decorators = node.decorators; diff --git a/src/flow.ts b/src/flow.ts index 061c1aacca..ac1bbc512d 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -413,9 +413,12 @@ export class Flow { /** Tests if this flow has any scoped locals that must be free'd. */ get hasScopedLocals(): bool { - if (this.scopedLocals) { - for (let scopedLocal of this.scopedLocals.values()) { - if (scopedLocal.is(CommonFlags.SCOPED)) { // otherwise an alias + var scopedLocals = this.scopedLocals; + if (scopedLocals) { + // for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); + if (local.is(CommonFlags.SCOPED)) { // otherwise an alias return true; } } @@ -425,10 +428,13 @@ export class Flow { /** Frees this flow's scoped variables and returns its parent flow. */ freeScopedLocals(): void { - if (this.scopedLocals) { - for (let scopedLocal of this.scopedLocals.values()) { - if (scopedLocal.is(CommonFlags.SCOPED)) { // otherwise an alias - this.freeTempLocal(scopedLocal); + var scopedLocals = this.scopedLocals; + if (scopedLocals) { + // for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); + if (local.is(CommonFlags.SCOPED)) { // otherwise an alias + this.freeTempLocal(local); } } this.scopedLocals = null; diff --git a/src/glue/binaryen.d.ts b/src/glue/binaryen.d.ts index 4b608b9e1d..284088ef8d 100644 --- a/src/glue/binaryen.d.ts +++ b/src/glue/binaryen.d.ts @@ -476,7 +476,7 @@ export declare function _BinaryenBinary(module: BinaryenModuleRef, op: BinaryenO export declare function _BinaryenSelect(module: BinaryenModuleRef, condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef, type: BinaryenType): BinaryenExpressionRef; export declare function _BinaryenDrop(module: BinaryenModuleRef, value: BinaryenExpressionRef): BinaryenExpressionRef; export declare function _BinaryenReturn(module: BinaryenModuleRef, value: BinaryenExpressionRef): BinaryenExpressionRef; -export declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: usize | 0, operands: usize, numOperands: BinaryenIndex): BinaryenExpressionRef; +export declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: usize, operands: usize, numOperands: BinaryenIndex): BinaryenExpressionRef; export declare function _BinaryenNop(module: BinaryenModuleRef): BinaryenExpressionRef; export declare function _BinaryenUnreachable(module: BinaryenModuleRef): BinaryenExpressionRef; diff --git a/src/glue/js/index.ts b/src/glue/js/index.ts index b0a101f9e3..fb9f71a11e 100644 --- a/src/glue/js/index.ts +++ b/src/glue/js/index.ts @@ -8,3 +8,4 @@ import "../../../std/portable/index"; import "../binaryen"; import "./float"; import "./i64"; +import "./mapset"; diff --git a/src/glue/js/mapset.d.ts b/src/glue/js/mapset.d.ts new file mode 100644 index 0000000000..7a5e8a5753 --- /dev/null +++ b/src/glue/js/mapset.d.ts @@ -0,0 +1,3 @@ +declare function Map_keys(map: Map): K[]; +declare function Map_values(map: Map): V[]; +declare function Set_values(set: Set): V[]; diff --git a/src/glue/js/mapset.js b/src/glue/js/mapset.js new file mode 100644 index 0000000000..8dfbc667c7 --- /dev/null +++ b/src/glue/js/mapset.js @@ -0,0 +1,23 @@ +global.Map_keys = function(map) { + var keys = []; + for (let key of map.keys()) { + keys.push(key); + } + return keys; +}; + +global.Map_values = function(map) { + var vals = []; + for (let val of map.values()) { + vals.push(val); + } + return vals; +}; + +global.Set_values = function(set) { + var vals = []; + for (let val of set.values()) { + vals.push(val); + } + return vals; +}; diff --git a/src/glue/wasm/index.ts b/src/glue/wasm/index.ts index 4742c5ad01..68e707ff4f 100644 --- a/src/glue/wasm/index.ts +++ b/src/glue/wasm/index.ts @@ -7,3 +7,4 @@ import "../binaryen.d"; import "./i64"; import "./float"; +import "./mapset"; diff --git a/src/glue/wasm/mapset.ts b/src/glue/wasm/mapset.ts new file mode 100644 index 0000000000..e31d2debc3 --- /dev/null +++ b/src/glue/wasm/mapset.ts @@ -0,0 +1,14 @@ +@global +function Map_keys(map: Map): K[] { + return map.keys(); // preliminary +} + +@global +function Map_values(map: Map): V[] { + return map.values(); // preliminary +} + +@global +function Set_values(set: Set): V[] { + return set.values(); // preliminary +} diff --git a/src/module.ts b/src/module.ts index e136f2a09d..f55f2e71ed 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1477,7 +1477,11 @@ export class Module { dispose(): void { assert(this.ref); - for (let ptr of this.cachedStrings.values()) binaryen._free(ptr); + // for (let ptr of this.cachedStrings.values()) { + for (let _values = Map_values(this.cachedStrings), i = 0, k = _values.length; i < k; ++i) { + let ptr = unchecked(_values[i]); + binaryen._free(ptr); + } this.cachedStrings = new Map(); binaryen._free(this.lit); binaryen._free(this.cachedPrecomputeNames); diff --git a/src/parser.ts b/src/parser.ts index a77639bd3f..ab22f68e62 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -64,7 +64,7 @@ import { ExportMember, ExportStatement, ExpressionStatement, - ForStatement, + ForOfStatement, FunctionDeclaration, IfStatement, ImportDeclaration, @@ -846,14 +846,15 @@ export class Parser extends DiagnosticEmitter { tn: Tokenizer, flags: CommonFlags, decorators: DecoratorNode[] | null, - startPos: i32 + startPos: i32, + isFor: bool = false ): VariableStatement | null { // at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'? var members = new Array(); do { - let member = this.parseVariableDeclaration(tn, flags, decorators); + let member = this.parseVariableDeclaration(tn, flags, decorators, isFor); if (!member) return null; members.push(member); } while (tn.skip(Token.COMMA)); @@ -866,7 +867,8 @@ export class Parser extends DiagnosticEmitter { parseVariableDeclaration( tn: Tokenizer, parentFlags: CommonFlags, - parentDecorators: DecoratorNode[] | null + parentDecorators: DecoratorNode[] | null, + isFor: bool = false ): VariableDeclaration | null { // before: Identifier (':' Type)? ('=' Expression)? @@ -892,7 +894,7 @@ export class Parser extends DiagnosticEmitter { var type: TypeNode | null = null; if (tn.skip(Token.COLON)) { - type = this.parseType(tn); + type = this.parseType(tn, true); } var initializer: Expression | null = null; @@ -905,7 +907,7 @@ export class Parser extends DiagnosticEmitter { } initializer = this.parseExpression(tn, Precedence.COMMA + 1); if (!initializer) return null; - } else { + } else if (!isFor) { if (flags & CommonFlags.CONST) { if (!(flags & CommonFlags.AMBIENT)) { this.error( @@ -2853,7 +2855,7 @@ export class Parser extends DiagnosticEmitter { parseForStatement( tn: Tokenizer - ): ForStatement | null { + ): Statement | null { // at 'for': '(' Statement? Expression? ';' Expression? ')' Statement @@ -2863,17 +2865,71 @@ export class Parser extends DiagnosticEmitter { let initializer: Statement | null = null; if (tn.skip(Token.CONST)) { - initializer = this.parseVariable(tn, CommonFlags.CONST, null, tn.tokenPos); + initializer = this.parseVariable(tn, CommonFlags.CONST, null, tn.tokenPos, true); } else if (tn.skip(Token.LET)) { - initializer = this.parseVariable(tn, CommonFlags.LET, null, tn.tokenPos); + initializer = this.parseVariable(tn, CommonFlags.LET, null, tn.tokenPos, true); } else if (tn.skip(Token.VAR)) { - initializer = this.parseVariable(tn, CommonFlags.NONE, null, tn.tokenPos); + initializer = this.parseVariable(tn, CommonFlags.NONE, null, tn.tokenPos, true); } else if (!tn.skip(Token.SEMICOLON)) { initializer = this.parseExpressionStatement(tn); if (!initializer) return null; } + if (initializer) { + if (tn.skip(Token.OF)) { + // TODO: for (let [key, val] of ...) + if (initializer.kind == NodeKind.EXPRESSION) { + if ((initializer).expression.kind != NodeKind.IDENTIFIER) { + this.error( + DiagnosticCode.Identifier_expected, + initializer.range + ); + return null; + } + return this.parseForOfStatement(tn, startPos, initializer); + } + if (initializer.kind == NodeKind.VARIABLE) { + let declarations = (initializer).declarations; + for (let i = 0, k = declarations.length; i < k; ++i) { + let declaration = declarations[i]; + if (declaration.initializer) { + this.error( + DiagnosticCode.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer, + declaration.initializer.range + ); // recoverable + } + } + return this.parseForOfStatement(tn, startPos, initializer); + } + this.error( + DiagnosticCode.Identifier_expected, + initializer.range + ); + return null; + } + // non-for..of needs type or initializer + if (initializer.kind == NodeKind.VARIABLE) { + let declarations = (initializer).declarations; + for (let i = 0, k = declarations.length; i < k; ++i) { + let declaration = declarations[i]; + if (!declaration.initializer) { + if (declaration.flags & CommonFlags.CONST) { + this.error( + DiagnosticCode._const_declarations_must_be_initialized, + declaration.name.range + ); + } else if (!declaration.type) { + this.error( + DiagnosticCode.Type_expected, + declaration.name.range.atEnd + ); + } + } + } + } + } + if (tn.token == Token.SEMICOLON) { let condition: ExpressionStatement | null = null; if (!tn.skip(Token.SEMICOLON)) { @@ -2930,6 +2986,36 @@ export class Parser extends DiagnosticEmitter { return null; } + parseForOfStatement( + tn: Tokenizer, + startPos: i32, + variable: Statement, + ): ForOfStatement | null { + + // at 'of': Expression ')' Statement + + var iterable = this.parseExpression(tn); + if (!iterable) return null; + + if (!tn.skip(Token.CLOSEPAREN)) { + this.error( + DiagnosticCode._0_expected, + tn.range(), ")" + ); + return null; + } + + var statement = this.parseStatement(tn); + if (!statement) return null; + + return Node.createForOfStatement( + variable, + iterable, + statement, + tn.range(startPos, tn.pos) + ); + } + parseIfStatement( tn: Tokenizer ): IfStatement | null { diff --git a/src/program.ts b/src/program.ts index de57361697..158ea37134 100644 --- a/src/program.ts +++ b/src/program.ts @@ -769,9 +769,12 @@ export class Program extends DiagnosticEmitter { } // queued exports * should be linkable now that all files have been processed - for (let [file, exportsStar] of queuedExportsStar) { - for (let i = 0, k = exportsStar.length; i < k; ++i) { - let exportStar = exportsStar[i]; + // for (let [file, starExports] of queuedExportsStar) { + for (let _keys = Map_keys(queuedExportsStar), i = 0, k = _keys.length; i < k; ++i) { + let file = _keys[i]; + let starExports = queuedExportsStar.get(file)!; + for (let j = 0, l = starExports.length; j < l; ++j) { + let exportStar = unchecked(starExports[j]); let foreignFile = this.lookupForeignFile(exportStar.foreignPath, exportStar.foreignPathAlt); if (!foreignFile) { this.error( @@ -828,8 +831,14 @@ export class Program extends DiagnosticEmitter { } // queued exports should be resolvable now that imports are finalized - for (let [file, exports] of queuedExports) { - for (let [exportName, queuedExport] of exports) { + // for (let [file, exports] of queuedExports) { + for (let _keys = Map_keys(queuedExports), i = 0, k = _keys.length; i < k; ++i) { + let file = unchecked(_keys[i]); + let exports = queuedExports.get(file)!; + // for (let [exportName, queuedExport] of exports) { + for (let exportNames = Map_keys(exports), j = 0, l = exportNames.length; j < l; ++j) { + let exportName = unchecked(exportNames[j]); + let queuedExport = exports.get(exportName)!; let localName = queuedExport.localIdentifier.text; let foreignPath = queuedExport.foreignPath; if (foreignPath) { // i.e. export { foo [as bar] } from "./baz" @@ -944,7 +953,10 @@ export class Program extends DiagnosticEmitter { { let globalAliases = options.globalAliases; if (globalAliases) { - for (let [alias, name] of globalAliases) { + // for (let [alias, name] of globalAliases) { + for (let _keys = Map_keys(globalAliases), i = 0, k = _keys.length; i < k; ++i) { + let alias = unchecked(_keys[i]); + let name = globalAliases.get(alias)!; if (!name.length) continue; // explicitly disabled let firstChar = name.charCodeAt(0); if (firstChar >= CharCode._0 && firstChar <= CharCode._9) { @@ -981,10 +993,15 @@ export class Program extends DiagnosticEmitter { this.allocArrayInstance = this.requireFunction(CommonNames.allocArray); // mark module exports, i.e. to apply proper wrapping behavior on the boundaries - for (let file of this.filesByName.values()) { + // for (let file of this.filesByName.values()) { + for (let _values = Map_values(this.filesByName), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); let exports = file.exports; if (exports !== null && file.source.sourceKind == SourceKind.USER_ENTRY) { - for (let element of exports.values()) this.markModuleExport(element); + for (let _values = Map_values(exports), j = 0, l = _values.length; j < l; ++j) { + let element = unchecked(_values[j]); + this.markModuleExport(element); + } } } } @@ -1026,7 +1043,13 @@ export class Program extends DiagnosticEmitter { switch (element.kind) { case ElementKind.CLASS_PROTOTYPE: { let instanceMembers = (element).instanceMembers; - if (instanceMembers) for (let member of instanceMembers.values()) this.markModuleExport(member); + if (instanceMembers) { + // for (let member of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.markModuleExport(member); + } + } break; } case ElementKind.PROPERTY_PROTOTYPE: { @@ -1042,8 +1065,14 @@ export class Program extends DiagnosticEmitter { case ElementKind.CLASS: assert(false); // assumes that there are no instances yet } { - let members = element.members; - if (members) for (let member of members.values()) this.markModuleExport(member); + let staticMembers = element.members; + if (staticMembers) { + // for (let member of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.markModuleExport(member); + } + } } } @@ -1993,9 +2022,10 @@ export class Program extends DiagnosticEmitter { /** Finds all cyclic classes. */ findCyclicClasses(): Set { - var managedClasses = this.managedClasses; var cyclics = new Set(); - for (let instance of managedClasses.values()) { + // for (let instance of this.managedClasses.values()) { + for (let _values = Map_values(this.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); if (!instance.isAcyclic) cyclics.add(instance); } return cyclics; @@ -2412,7 +2442,10 @@ export class File extends Element { ); var exports = this.exports; if (exports) { - for (let [memberName, member] of exports) { + // for (let [memberName, member] of exports) { + for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = exports.get(memberName)!; ns.add(memberName, member); } } @@ -3436,7 +3469,10 @@ export class Class extends TypedElement { var inheritedTypeArguments = base.contextualTypeArguments; if (inheritedTypeArguments) { let contextualTypeArguments = this.contextualTypeArguments; - for (let [baseName, baseType] of inheritedTypeArguments) { + // for (let [baseName, baseType] of inheritedTypeArguments) { + for (let _keys = Map_keys(inheritedTypeArguments), i = 0, k = _keys.length; i < k; ++i) { + let baseName = unchecked(_keys[i]); + let baseType = inheritedTypeArguments.get(baseName)!; if (!contextualTypeArguments) { this.contextualTypeArguments = contextualTypeArguments = new Map(); contextualTypeArguments.set(baseName, baseType); @@ -3605,13 +3641,15 @@ export class Class extends TypedElement { // Find out if any field references 'other' directly or indirectly var current: Class | null; - var members = this.members; - if (members) { - for (let member of members.values()) { + var instanceMembers = this.members; + if (instanceMembers) { + // for (let member of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.kind == ElementKind.FIELD) { - let type = (member).type; - if (type.is(TypeFlags.REFERENCE)) { - if ((current = type.classReference) !== null && ( + let fieldType = (member).type; + if (fieldType.is(TypeFlags.REFERENCE)) { + if ((current = fieldType.classReference) !== null && ( current === other || current.cyclesTo(other, except) )) return true; @@ -3819,7 +3857,10 @@ function copyMembers(src: Element, dest: Element): void { if (srcMembers) { let destMembers = dest.members; if (!destMembers) dest.members = destMembers = new Map(); - for (let [memberName, member] of srcMembers) { + // for (let [memberName, member] of srcMembers) { + for (let _keys = Map_keys(srcMembers), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = srcMembers.get(memberName)!; destMembers.set(memberName, member); } } diff --git a/src/resolver.ts b/src/resolver.ts index 0cd448561b..b012e35d5e 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2913,7 +2913,10 @@ export class Resolver extends DiagnosticEmitter { assert(!pendingClasses.includes(base)); let baseMembers = base.members; if (baseMembers) { - for (let [baseMemberName, baseMember] of baseMembers) { + // for (let [baseMemberName, baseMember] of baseMembers) { + for (let _keys = Map_keys(baseMembers), i = 0, k = _keys.length; i < k; ++i) { + let baseMemberName = unchecked(_keys[i]); + let baseMember = baseMembers.get(baseMemberName)!; instanceMembers.set(baseMemberName, baseMember); } } @@ -2924,7 +2927,9 @@ export class Resolver extends DiagnosticEmitter { var prototype = instance.prototype; var instanceMemberPrototypes = prototype.instanceMembers; if (instanceMemberPrototypes) { - for (let member of instanceMemberPrototypes.values()) { + // for (let member of instanceMemberPrototypes.values()) { + for (let _values = Map_values(instanceMemberPrototypes), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); switch (member.kind) { case ElementKind.FIELD_PROTOTYPE: { @@ -3031,8 +3036,12 @@ export class Resolver extends DiagnosticEmitter { } // Fully resolve operator overloads (don't have type parameters on their own) - for (let [kind, overloadPrototype] of prototype.overloadPrototypes) { - assert(kind != OperatorKind.INVALID); + var overloadPrototypes = prototype.overloadPrototypes; + // for (let [overloadKind, overloadPrototype] of overloadPrototypes) { + for (let _keys = Map_keys(overloadPrototypes), i = 0, k = _keys.length; i < k; ++i) { + let overloadKind = unchecked(_keys[i]); + let overloadPrototype = overloadPrototypes.get(overloadKind)!; + assert(overloadKind != OperatorKind.INVALID); let operatorInstance: Function | null; if (overloadPrototype.is(CommonFlags.INSTANCE)) { let boundPrototype = overloadPrototype.toBound(instance); @@ -3057,7 +3066,7 @@ export class Resolver extends DiagnosticEmitter { // the corresponding value, thus requiring a matching return type, while a // static overload works like any other overload. if (operatorInstance.is(CommonFlags.INSTANCE)) { - switch (kind) { + switch (overloadKind) { case OperatorKind.PREFIX_INC: case OperatorKind.PREFIX_DEC: case OperatorKind.POSTFIX_INC: @@ -3074,12 +3083,12 @@ export class Resolver extends DiagnosticEmitter { } } } - if (!overloads.has(kind)) { - overloads.set(kind, operatorInstance); - if (kind == OperatorKind.INDEXED_GET || kind == OperatorKind.INDEXED_SET) { + if (!overloads.has(overloadKind)) { + overloads.set(overloadKind, operatorInstance); + if (overloadKind == OperatorKind.INDEXED_GET || overloadKind == OperatorKind.INDEXED_SET) { let index = instance.indexSignature; if (!index) instance.indexSignature = index = new IndexSignature(instance); - if (kind == OperatorKind.INDEXED_GET) { + if (overloadKind == OperatorKind.INDEXED_GET) { index.setType(operatorInstance.signature.returnType); } } diff --git a/src/util/collections.ts b/src/util/collections.ts index db47579cf5..972e199299 100644 --- a/src/util/collections.ts +++ b/src/util/collections.ts @@ -11,7 +11,11 @@ export function makeArray(original: Array | null = null): Array { export function makeSet(original: Set | null = null): Set { if (original) { let cloned = new Set(); - for (let v of original) cloned.add(v); + // for (let v of original) { + for (let _values = Set_values(original), i = 0, k = _values.length; i < k; ++i) { + let v = unchecked(_values[i]); + cloned.add(v); + } return cloned; } return new Set(); @@ -20,10 +24,20 @@ export function makeSet(original: Set | null = null): Set { export function makeMap(original: Map | null = null, overrides: Map | null = null): Map { var cloned = new Map(); if (original) { - for (let [k, v] of original) cloned.set(k, v); - if (overrides) for (let [k, v] of overrides) cloned.set(k, v); - } else if (overrides) { - for (let [k, v] of overrides) cloned.set(k, v); + // for (let [k, v] of original) { + for (let _keys = Map_keys(original), i = 0, k = _keys.length; i < k; ++i) { + let k = unchecked(_keys[i]); + let v = original.get(k)!; + cloned.set(k, v); + } + } + if (overrides) { + // for (let [k, v] of overrides) { + for (let _keys = Map_keys(overrides), i = 0, k = _keys.length; i < k; ++i) { + let k = unchecked(_keys[i]); + let v = overrides.get(k)!; + cloned.set(k, v); + } } return cloned; } diff --git a/tests/parser/forof.ts b/tests/parser/forof.ts new file mode 100644 index 0000000000..3cab01d38c --- /dev/null +++ b/tests/parser/forof.ts @@ -0,0 +1,16 @@ +for (foo of bar) { + ; +} +for (var foo of bar) { + ; +} +for (let foo of bar) { + ; +} +for (const foo of bar) { + ; +} +for (foo of bar) ; +for (var foo of bar) ; +for (let foo of bar) ; +for (const foo of bar) ; diff --git a/tests/parser/forof.ts.fixture.ts b/tests/parser/forof.ts.fixture.ts new file mode 100644 index 0000000000..3cab01d38c --- /dev/null +++ b/tests/parser/forof.ts.fixture.ts @@ -0,0 +1,16 @@ +for (foo of bar) { + ; +} +for (var foo of bar) { + ; +} +for (let foo of bar) { + ; +} +for (const foo of bar) { + ; +} +for (foo of bar) ; +for (var foo of bar) ; +for (let foo of bar) ; +for (const foo of bar) ; From 1aa5616bbe0e975a680f026a73218bdf337a061c Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 28 Feb 2020 00:59:49 +0100 Subject: [PATCH 03/28] fix identifier handling, don't use abstract --- src/compiler.ts | 9 ++++++++- src/definitions.ts | 16 ++++++++-------- src/parser.ts | 4 ++-- src/program.ts | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 22a2690ac0..c11a93e06b 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -549,7 +549,14 @@ export class Compiler extends DiagnosticEmitter { /** Applies the respective module exports for the specified file. */ private ensureModuleExports(file: File): void { var members = file.exports; - if (members) for (let [name, member] of members) this.ensureModuleExport(name, member); + if (members) { + // for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = members.get(memberName)!; + this.ensureModuleExport(memberName, member); + } + } var exportsStar = file.exportsStar; if (exportsStar) { for (let i = 0, k = exportsStar.length; i < k; ++i) this.ensureModuleExports(exportsStar[i]); diff --git a/src/definitions.ts b/src/definitions.ts index b0527170eb..8bd3fcf8c7 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -168,14 +168,14 @@ export abstract class ExportsWalker { assert(false); } - abstract visitGlobal(name: string, element: Global): void; - abstract visitEnum(name: string, element: Enum): void; - abstract visitFunction(name: string, element: Function): void; - abstract visitClass(name: string, element: Class): void; - abstract visitInterface(name: string, element: Interface): void; - abstract visitField(name: string, element: Field): void; - abstract visitNamespace(name: string, element: Element): void; - abstract visitAlias(name: string, element: Element, originalName: string): void; + /* abstract */ visitGlobal(name: string, element: Global): void { unreachable(); } + /* abstract */ visitEnum(name: string, element: Enum): void { unreachable(); } + /* abstract */ visitFunction(name: string, element: Function): void { unreachable(); } + /* abstract */ visitClass(name: string, element: Class): void { unreachable(); } + /* abstract */ visitInterface(name: string, element: Interface): void { unreachable(); } + /* abstract */ visitField(name: string, element: Field): void { unreachable(); } + /* abstract */ visitNamespace(name: string, element: Element): void { unreachable(); } + /* abstract */ visitAlias(name: string, element: Element, originalName: string): void { unreachable(); } } /** A WebIDL definitions builder. */ diff --git a/src/parser.ts b/src/parser.ts index ab22f68e62..f1aca3ea11 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1977,7 +1977,7 @@ export class Parser extends DiagnosticEmitter { tn.skip(Token.SEMICOLON); return retIndex; } - if (!tn.skipIdentifier()) { + if (!tn.skipIdentifier(IdentifierHandling.ALWAYS)) { this.error( DiagnosticCode.Identifier_expected, tn.range() @@ -3901,7 +3901,7 @@ export class Parser extends DiagnosticEmitter { } // PropertyAccessExpression case Token.DOT: { - if (tn.skipIdentifier()) { // expr '.' Identifier + if (tn.skipIdentifier(IdentifierHandling.ALWAYS)) { // expr '.' Identifier let next = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); expr = Node.createPropertyAccessExpression( expr, diff --git a/src/program.ts b/src/program.ts index 158ea37134..c4e6990f38 100644 --- a/src/program.ts +++ b/src/program.ts @@ -2188,7 +2188,7 @@ export abstract class Element { } /** Looks up the element with the specified name relative to this element, like in JS. */ - abstract lookup(name: string): Element | null; + /* abstract */ lookup(name: string): Element | null { return unreachable(); } /** Adds an element as a member of this one. Reports and returns `false` if a duplicate. */ add(name: string, element: DeclaredElement): bool { From ddefdf06d14e6b0b9764c4567a74e40433625f34 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 28 Feb 2020 01:49:21 +0100 Subject: [PATCH 04/28] move .kind initializers --- src/ast.ts | 966 +++++++++++++++++++++++++---------------------------- 1 file changed, 455 insertions(+), 511 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index bc6c8958a8..06dff06ffd 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -115,7 +115,6 @@ export function nodeIsConstantValue(kind: NodeKind): bool { /** Base class of all nodes. */ export abstract class Node { - /** Node kind indicator. */ kind: NodeKind; /** Source range. */ @@ -127,11 +126,12 @@ export abstract class Node { name: IdentifierExpression, range: Range ): TypeName { - var typeName = new TypeName(); - typeName.range = range; - typeName.identifier = name; - typeName.next = null; - return typeName; + var node = new TypeName(); + node.kind = NodeKind.TYPENAME; + node.range = range; + node.identifier = name; + node.next = null; + return node; } static createSimpleTypeName( @@ -147,12 +147,13 @@ export abstract class Node { isNullable: bool, range: Range ): NamedTypeNode { - var type = new NamedTypeNode(); - type.range = range; - type.name = name; - type.typeArguments = typeArguments; - type.isNullable = isNullable; - return type; + var node = new NamedTypeNode(); + node.kind = NodeKind.NAMEDTYPE; + node.range = range; + node.name = name; + node.typeArguments = typeArguments; + node.isNullable = isNullable; + return node; } static createFunctionType( @@ -162,13 +163,14 @@ export abstract class Node { isNullable: bool, range: Range ): FunctionTypeNode { - var type = new FunctionTypeNode(); - type.range = range; - type.parameters = parameters; - type.returnType = returnType; - type.explicitThisType = explicitThisType; - type.isNullable = isNullable; - return type; + var node = new FunctionTypeNode(); + node.kind = NodeKind.FUNCTIONTYPE; + node.range = range; + node.parameters = parameters; + node.returnType = returnType; + node.explicitThisType = explicitThisType; + node.isNullable = isNullable; + return node; } static createOmittedType( @@ -188,12 +190,13 @@ export abstract class Node { defaultType: NamedTypeNode | null, range: Range ): TypeParameterNode { - var elem = new TypeParameterNode(); - elem.range = range; - elem.name = name; - elem.extendsType = extendsType; - elem.defaultType = defaultType; - return elem; + var node = new TypeParameterNode(); + node.kind = NodeKind.TYPEPARAMETER; + node.range = range; + node.name = name; + node.extendsType = extendsType; + node.defaultType = defaultType; + return node; } static createParameter( @@ -203,13 +206,14 @@ export abstract class Node { kind: ParameterKind, range: Range ): ParameterNode { - var elem = new ParameterNode(); - elem.range = range; - elem.name = name; - elem.type = type; - elem.initializer = initializer; - elem.parameterKind = kind; - return elem; + var node = new ParameterNode(); + node.kind = NodeKind.PARAMETER; + node.range = range; + node.name = name; + node.type = type; + node.initializer = initializer; + node.parameterKind = kind; + return node; } // special @@ -219,12 +223,13 @@ export abstract class Node { args: Expression[] | null, range: Range ): DecoratorNode { - var stmt = new DecoratorNode(); - stmt.range = range; - stmt.name = name; - stmt.arguments = args; - stmt.decoratorKind = DecoratorKind.fromNode(name); - return stmt; + var node = new DecoratorNode(); + node.kind = NodeKind.DECORATOR; + node.range = range; + node.name = name; + node.arguments = args; + node.decoratorKind = DecoratorKind.fromNode(name); + return node; } static createComment( @@ -233,6 +238,7 @@ export abstract class Node { range: Range ): CommentNode { var node = new CommentNode(); + node.kind = NodeKind.COMMENT; node.range = range; node.commentKind = kind; node.text = text; @@ -246,30 +252,34 @@ export abstract class Node { range: Range, isQuoted: bool = false ): IdentifierExpression { - var expr = new IdentifierExpression(); - expr.range = range; - expr.text = name; - expr.isQuoted = isQuoted; - return expr; + var node = new IdentifierExpression(); + node.kind = NodeKind.IDENTIFIER; + node.range = range; + node.text = name; + node.isQuoted = isQuoted; + return node; } static createEmptyIdentifierExpression( range: Range ): IdentifierExpression { - var expr = new IdentifierExpression(); - expr.range = range; - expr.text = ""; - return expr; + var node = new IdentifierExpression(); + node.kind = NodeKind.IDENTIFIER; + node.range = range; + node.text = ""; + return node; } static createArrayLiteralExpression( elements: (Expression | null)[], range: Range ): ArrayLiteralExpression { - var expr = new ArrayLiteralExpression(); - expr.range = range; - expr.elementExpressions = elements; - return expr; + var node = new ArrayLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.range = range; + node.literalKind = LiteralKind.ARRAY; + node.elementExpressions = elements; + return node; } static createAssertionExpression( @@ -278,12 +288,13 @@ export abstract class Node { toType: TypeNode | null, range: Range ): AssertionExpression { - var expr = new AssertionExpression(); - expr.range = range; - expr.assertionKind = assertionKind; - expr.expression = expression; - expr.toType = toType; - return expr; + var node = new AssertionExpression(); + node.kind = NodeKind.ASSERTION; + node.range = range; + node.assertionKind = assertionKind; + node.expression = expression; + node.toType = toType; + return node; } static createBinaryExpression( @@ -292,12 +303,13 @@ export abstract class Node { right: Expression, range: Range ): BinaryExpression { - var expr = new BinaryExpression(); - expr.range = range; - expr.operator = operator; - expr.left = left; - expr.right = right; - return expr; + var node = new BinaryExpression(); + node.kind = NodeKind.BINARY; + node.range = range; + node.operator = operator; + node.left = left; + node.right = right; + return node; } static createCallExpression( @@ -306,39 +318,44 @@ export abstract class Node { args: Expression[], range: Range ): CallExpression { - var expr = new CallExpression(); - expr.range = range; - expr.expression = expression; - expr.typeArguments = typeArgs; - expr.arguments = args; - return expr; + var node = new CallExpression(); + node.kind = NodeKind.CALL; + node.range = range; + node.expression = expression; + node.typeArguments = typeArgs; + node.arguments = args; + return node; } static createClassExpression( declaration: ClassDeclaration ): ClassExpression { - var expr = new ClassExpression(); - expr.range = declaration.range; - expr.declaration = declaration; - return expr; + var node = new ClassExpression(); + node.kind = NodeKind.CLASS; + node.range = declaration.range; + node.declaration = declaration; + return node; } static createCommaExpression( expressions: Expression[], range: Range ): CommaExpression { - var expr = new CommaExpression(); - expr.range = range; - expr.expressions = expressions; - return expr; + var node = new CommaExpression(); + node.kind = NodeKind.COMMA; + node.range = range; + node.expressions = expressions; + return node; } static createConstructorExpression( range: Range ): ConstructorExpression { - var expr = new ConstructorExpression(); - expr.range = range; - return expr; + var node = new ConstructorExpression(); + node.kind = NodeKind.CONSTRUCTOR; + node.range = range; + node.text = "constructor"; + return node; } static createElementAccessExpression( @@ -346,38 +363,44 @@ export abstract class Node { element: Expression, range: Range ): ElementAccessExpression { - var expr = new ElementAccessExpression(); - expr.range = range; - expr.expression = expression; - expr.elementExpression = element; - return expr; + var node = new ElementAccessExpression(); + node.kind = NodeKind.ELEMENTACCESS; + node.range = range; + node.expression = expression; + node.elementExpression = element; + return node; } static createFalseExpression( range: Range ): FalseExpression { - var expr = new FalseExpression(); - expr.range = range; - return expr; + var node = new FalseExpression(); + node.kind = NodeKind.FALSE; + node.range = range; + node.text = "false"; + return node; } static createFloatLiteralExpression( value: f64, range: Range ): FloatLiteralExpression { - var expr = new FloatLiteralExpression(); - expr.range = range; - expr.value = value; - return expr; + var node = new FloatLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.FLOAT; + node.range = range; + node.value = value; + return node; } static createFunctionExpression( declaration: FunctionDeclaration ): FunctionExpression { - var expr = new FunctionExpression(); - expr.range = declaration.range; - expr.declaration = declaration; - return expr; + var node = new FunctionExpression(); + node.kind = NodeKind.FUNCTION; + node.range = declaration.range; + node.declaration = declaration; + return node; } static createInstanceOfExpression( @@ -385,21 +408,24 @@ export abstract class Node { isType: TypeNode, range: Range ): InstanceOfExpression { - var expr = new InstanceOfExpression(); - expr.range = range; - expr.expression = expression; - expr.isType = isType; - return expr; + var node = new InstanceOfExpression(); + node.kind = NodeKind.INSTANCEOF; + node.range = range; + node.expression = expression; + node.isType = isType; + return node; } static createIntegerLiteralExpression( value: I64, range: Range ): IntegerLiteralExpression { - var expr = new IntegerLiteralExpression(); - expr.range = range; - expr.value = value; - return expr; + var node = new IntegerLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.INTEGER; + node.range = range; + node.value = value; + return node; } static createNewExpression( @@ -408,20 +434,23 @@ export abstract class Node { args: Expression[], range: Range ): NewExpression { - var expr = new NewExpression(); - expr.range = range; - expr.typeName = typeName; - expr.typeArguments = typeArgs; - expr.arguments = args; - return expr; + var node = new NewExpression(); + node.kind = NodeKind.NEW; + node.range = range; + node.typeName = typeName; + node.typeArguments = typeArgs; + node.arguments = args; + return node; } static createNullExpression( range: Range ): NullExpression { - var expr = new NullExpression(); - expr.range = range; - return expr; + var node = new NullExpression(); + node.kind = NodeKind.NULL; + node.range = range; + node.text = "null"; + return node; } static createObjectLiteralExpression( @@ -429,21 +458,24 @@ export abstract class Node { values: Expression[], range: Range ): ObjectLiteralExpression { - var expr = new ObjectLiteralExpression(); - expr.range = range; - expr.names = names; - expr.values = values; - return expr; + var node = new ObjectLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.OBJECT; + node.range = range; + node.names = names; + node.values = values; + return node; } static createParenthesizedExpression( expression: Expression, range: Range ): ParenthesizedExpression { - var expr = new ParenthesizedExpression(); - expr.range = range; - expr.expression = expression; - return expr; + var node = new ParenthesizedExpression(); + node.kind = NodeKind.PARENTHESIZED; + node.range = range; + node.expression = expression; + return node; } static createPropertyAccessExpression( @@ -451,11 +483,12 @@ export abstract class Node { property: IdentifierExpression, range: Range ): PropertyAccessExpression { - var expr = new PropertyAccessExpression(); - expr.range = range; - expr.expression = expression; - expr.property = property; - return expr; + var node = new PropertyAccessExpression(); + node.kind = NodeKind.PROPERTYACCESS; + node.range = range; + node.expression = expression; + node.property = property; + return node; } static createRegexpLiteralExpression( @@ -463,11 +496,13 @@ export abstract class Node { flags: string, range: Range ): RegexpLiteralExpression { - var expr = new RegexpLiteralExpression(); - expr.range = range; - expr.pattern = pattern; - expr.patternFlags = flags; - return expr; + var node = new RegexpLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.REGEXP; + node.range = range; + node.pattern = pattern; + node.patternFlags = flags; + return node; } static createTernaryExpression( @@ -476,46 +511,55 @@ export abstract class Node { ifElse: Expression, range: Range ): TernaryExpression { - var expr = new TernaryExpression(); - expr.range = range; - expr.condition = condition; - expr.ifThen = ifThen; - expr.ifElse = ifElse; - return expr; + var node = new TernaryExpression(); + node.kind = NodeKind.TERNARY; + node.range = range; + node.condition = condition; + node.ifThen = ifThen; + node.ifElse = ifElse; + return node; } static createStringLiteralExpression( value: string, range: Range ): StringLiteralExpression { - var expr = new StringLiteralExpression(); - expr.range = range; - expr.value = value; - return expr; + var node = new StringLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.STRING; + node.range = range; + node.value = value; + return node; } static createSuperExpression( range: Range ): SuperExpression { - var expr = new SuperExpression(); - expr.range = range; - return expr; + var node = new SuperExpression(); + node.kind = NodeKind.SUPER; + node.range = range; + node.text = "super"; + return node; } static createThisExpression( range: Range ): ThisExpression { - var expr = new ThisExpression(); - expr.range = range; - return expr; + var node = new ThisExpression(); + node.kind = NodeKind.THIS; + node.range = range; + node.text = "this"; + return node; } static createTrueExpression( range: Range ): TrueExpression { - var expr = new TrueExpression(); - expr.range = range; - return expr; + var node = new TrueExpression(); + node.kind = NodeKind.TRUE; + node.range = range; + node.text = "true"; + return node; } static createUnaryPostfixExpression( @@ -523,11 +567,12 @@ export abstract class Node { operand: Expression, range: Range ): UnaryPostfixExpression { - var expr = new UnaryPostfixExpression(); - expr.range = range; - expr.operator = operator; - expr.operand = operand; - return expr; + var node = new UnaryPostfixExpression(); + node.kind = NodeKind.UNARYPOSTFIX; + node.range = range; + node.operator = operator; + node.operand = operand; + return node; } static createUnaryPrefixExpression( @@ -535,11 +580,12 @@ export abstract class Node { operand: Expression, range: Range ): UnaryPrefixExpression { - var expr = new UnaryPrefixExpression(); - expr.range = range; - expr.operator = operator; - expr.operand = operand; - return expr; + var node = new UnaryPrefixExpression(); + node.kind = NodeKind.UNARYPREFIX; + node.range = range; + node.operator = operator; + node.operand = operand; + return node; } // statements @@ -548,20 +594,22 @@ export abstract class Node { statements: Statement[], range: Range ): BlockStatement { - var stmt = new BlockStatement(); - stmt.range = range; - stmt.statements = statements; - return stmt; + var node = new BlockStatement(); + node.kind = NodeKind.BLOCK; + node.range = range; + node.statements = statements; + return node; } static createBreakStatement( label: IdentifierExpression | null, range: Range ): BreakStatement { - var stmt = new BreakStatement(); - stmt.range = range; - stmt.label = label; - return stmt; + var node = new BreakStatement(); + node.kind = NodeKind.BREAK; + node.range = range; + node.label = label; + return node; } static createClassDeclaration( @@ -574,26 +622,28 @@ export abstract class Node { flags: CommonFlags, range: Range ): ClassDeclaration { - var stmt = new ClassDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = identifier; - stmt.typeParameters = typeParameters; - stmt.extendsType = extendsType; - stmt.implementsTypes = implementsTypes; - stmt.members = members; - stmt.decorators = decorators; - return stmt; + var node = new ClassDeclaration(); + node.kind = NodeKind.CLASSDECLARATION; + node.range = range; + node.flags = flags; + node.name = identifier; + node.typeParameters = typeParameters; + node.extendsType = extendsType; + node.implementsTypes = implementsTypes; + node.members = members; + node.decorators = decorators; + return node; } static createContinueStatement( label: IdentifierExpression | null, range: Range ): ContinueStatement { - var stmt = new ContinueStatement(); - stmt.range = range; - stmt.label = label; - return stmt; + var node = new ContinueStatement(); + node.kind = NodeKind.CONTINUE; + node.range = range; + node.label = label; + return node; } static createDoStatement( @@ -601,19 +651,21 @@ export abstract class Node { condition: Expression, range: Range ): DoStatement { - var stmt = new DoStatement(); - stmt.range = range; - stmt.statement = statement; - stmt.condition = condition; - return stmt; + var node = new DoStatement(); + node.kind = NodeKind.DO; + node.range = range; + node.statement = statement; + node.condition = condition; + return node; } static createEmptyStatement( range: Range ): EmptyStatement { - var stmt = new EmptyStatement(); - stmt.range = range; - return stmt; + var node = new EmptyStatement(); + node.kind = NodeKind.EMPTY; + node.range = range; + return node; } static createEnumDeclaration( @@ -623,13 +675,14 @@ export abstract class Node { flags: CommonFlags, range: Range ): EnumDeclaration { - var stmt = new EnumDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.values = members; - stmt.decorators = decorators; - return stmt; + var node = new EnumDeclaration(); + node.kind = NodeKind.ENUMDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.values = members; + node.decorators = decorators; + return node; } static createEnumValueDeclaration( @@ -638,12 +691,13 @@ export abstract class Node { flags: CommonFlags, range: Range ): EnumValueDeclaration { - var stmt = new EnumValueDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.value = value; - return stmt; + var node = new EnumValueDeclaration(); + node.kind = NodeKind.ENUMVALUEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.value = value; + return node; } static createExportStatement( @@ -652,10 +706,11 @@ export abstract class Node { isDeclare: bool, range: Range ): ExportStatement { - var stmt = new ExportStatement(); - stmt.range = range; - stmt.members = members; - stmt.path = path; + var node = new ExportStatement(); + node.kind = NodeKind.EXPORT; + node.range = range; + node.members = members; + node.path = path; if (path) { let normalizedPath = normalizePath(path.value); if (path.value.startsWith(".")) { // relative @@ -663,22 +718,23 @@ export abstract class Node { } else { // absolute if (!normalizedPath.startsWith(LIBRARY_PREFIX)) normalizedPath = LIBRARY_PREFIX + normalizedPath; } - stmt.internalPath = mangleInternalPath(normalizedPath); + node.internalPath = mangleInternalPath(normalizedPath); } else { - stmt.internalPath = null; + node.internalPath = null; } - stmt.isDeclare = isDeclare; - return stmt; + node.isDeclare = isDeclare; + return node; } static createExportDefaultStatement( declaration: DeclarationStatement, range: Range ): ExportDefaultStatement { - var stmt = new ExportDefaultStatement(); - stmt.declaration = declaration; - stmt.range = range; - return stmt; + var node = new ExportDefaultStatement(); + node.kind = NodeKind.EXPORTDEFAULT; + node.declaration = declaration; + node.range = range; + return node; } static createExportImportStatement( @@ -686,11 +742,12 @@ export abstract class Node { externalName: IdentifierExpression, range: Range ): ExportImportStatement { - var stmt = new ExportImportStatement(); - stmt.range = range; - stmt.name = name; - stmt.externalName = externalName; - return stmt; + var node = new ExportImportStatement(); + node.kind = NodeKind.EXPORTIMPORT; + node.range = range; + node.name = name; + node.externalName = externalName; + return node; } static createExportMember( @@ -698,21 +755,23 @@ export abstract class Node { externalName: IdentifierExpression | null, range: Range ): ExportMember { - var elem = new ExportMember(); - elem.range = range; - elem.localName = name; + var node = new ExportMember(); + node.kind = NodeKind.EXPORTMEMBER; + node.range = range; + node.localName = name; if (!externalName) externalName = name; - elem.exportedName = externalName; - return elem; + node.exportedName = externalName; + return node; } static createExpressionStatement( expression: Expression ): ExpressionStatement { - var stmt = new ExpressionStatement(); - stmt.range = expression.range; - stmt.expression = expression; - return stmt; + var node = new ExpressionStatement(); + node.kind = NodeKind.EXPRESSION; + node.range = expression.range; + node.expression = expression; + return node; } static createIfStatement( @@ -721,12 +780,13 @@ export abstract class Node { ifFalse: Statement | null, range: Range ): IfStatement { - var stmt = new IfStatement(); - stmt.range = range; - stmt.condition = condition; - stmt.ifTrue = ifTrue; - stmt.ifFalse = ifFalse; - return stmt; + var node = new IfStatement(); + node.kind = NodeKind.IF; + node.range = range; + node.condition = condition; + node.ifTrue = ifTrue; + node.ifFalse = ifFalse; + return node; } static createImportStatement( @@ -734,19 +794,20 @@ export abstract class Node { path: StringLiteralExpression, range: Range ): ImportStatement { - var stmt = new ImportStatement(); - stmt.range = range; - stmt.declarations = decls; - stmt.namespaceName = null; - stmt.path = path; + var node = new ImportStatement(); + node.kind = NodeKind.IMPORT; + node.range = range; + node.declarations = decls; + node.namespaceName = null; + node.path = path; var normalizedPath = normalizePath(path.value); if (path.value.startsWith(".")) { // relative in project normalizedPath = resolvePath(normalizedPath, range.source.internalPath); } else { // absolute in library if (!normalizedPath.startsWith(LIBRARY_PREFIX)) normalizedPath = LIBRARY_PREFIX + normalizedPath; } - stmt.internalPath = mangleInternalPath(normalizedPath); - return stmt; + node.internalPath = mangleInternalPath(normalizedPath); + return node; } static createImportStatementWithWildcard( @@ -754,19 +815,20 @@ export abstract class Node { path: StringLiteralExpression, range: Range ): ImportStatement { - var stmt = new ImportStatement(); - stmt.range = range; - stmt.declarations = null; - stmt.namespaceName = identifier; - stmt.path = path; + var node = new ImportStatement(); + node.kind = NodeKind.IMPORT; + node.range = range; + node.declarations = null; + node.namespaceName = identifier; + node.path = path; var normalizedPath = normalizePath(path.value); if (path.value.startsWith(".")) { normalizedPath = resolvePath(normalizedPath, range.source.internalPath); } else { if (!normalizedPath.startsWith(LIBRARY_PREFIX)) normalizedPath = LIBRARY_PREFIX + normalizedPath; } - stmt.internalPath = mangleInternalPath(normalizedPath); - return stmt; + node.internalPath = mangleInternalPath(normalizedPath); + return node; } static createImportDeclaration( @@ -774,12 +836,13 @@ export abstract class Node { name: IdentifierExpression | null, range: Range ): ImportDeclaration { - var elem = new ImportDeclaration(); - elem.range = range; - elem.foreignName = foreignName; + var node = new ImportDeclaration(); + node.kind = NodeKind.IMPORTDECLARATION; + node.range = range; + node.foreignName = foreignName; if (!name) name = foreignName; - elem.name = name; - return elem; + node.name = name; + return node; } static createInterfaceDeclaration( @@ -791,15 +854,16 @@ export abstract class Node { flags: CommonFlags, range: Range ): InterfaceDeclaration { - var stmt = new InterfaceDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.extendsType = extendsType; - stmt.members = members; - stmt.decorators = decorators; - return stmt; + var node = new InterfaceDeclaration(); + node.kind = NodeKind.INTERFACEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.extendsType = extendsType; + node.members = members; + node.decorators = decorators; + return node; } static createFieldDeclaration( @@ -810,14 +874,15 @@ export abstract class Node { flags: CommonFlags, range: Range ): FieldDeclaration { - var stmt = new FieldDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.type = type; - stmt.initializer = initializer; - stmt.decorators = decorators; - return stmt; + var node = new FieldDeclaration(); + node.kind = NodeKind.FIELDDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.type = type; + node.initializer = initializer; + node.decorators = decorators; + return node; } static createForStatement( @@ -827,13 +892,14 @@ export abstract class Node { statement: Statement, range: Range ): ForStatement { - var stmt = new ForStatement(); - stmt.range = range; - stmt.initializer = initializer; - stmt.condition = condition; - stmt.incrementor = incrementor; - stmt.statement = statement; - return stmt; + var node = new ForStatement(); + node.kind = NodeKind.FOR; + node.range = range; + node.initializer = initializer; + node.condition = condition; + node.incrementor = incrementor; + node.statement = statement; + return node; } static createForOfStatement( @@ -842,12 +908,13 @@ export abstract class Node { statement: Statement, range: Range ): ForOfStatement { - var stmt = new ForOfStatement(); - stmt.range = range; - stmt.variable = variable; - stmt.iterable = iterable; - stmt.statement = statement; - return stmt; + var node = new ForOfStatement(); + node.kind = NodeKind.FOROF; + node.range = range; + node.variable = variable; + node.iterable = iterable; + node.statement = statement; + return node; } static createFunctionDeclaration( @@ -860,16 +927,17 @@ export abstract class Node { arrowKind: ArrowKind, range: Range ): FunctionDeclaration { - var stmt = new FunctionDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.signature = signature; - stmt.body = body; - stmt.decorators = decorators; - stmt.arrowKind = arrowKind; - return stmt; + var node = new FunctionDeclaration(); + node.kind = NodeKind.FUNCTIONDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.signature = signature; + node.body = body; + node.decorators = decorators; + node.arrowKind = arrowKind; + return node; } static createIndexSignatureDeclaration( @@ -878,12 +946,13 @@ export abstract class Node { flags: CommonFlags, range: Range ): IndexSignatureDeclaration { - var elem = new IndexSignatureDeclaration(); - elem.range = range; - elem.keyType = keyType; - elem.valueType = valueType; - elem.flags = flags; - return elem; + var node = new IndexSignatureDeclaration(); + node.kind = NodeKind.INDEXSIGNATUREDECLARATION; + node.range = range; + node.keyType = keyType; + node.valueType = valueType; + node.flags = flags; + return node; } static createMethodDeclaration( @@ -895,15 +964,16 @@ export abstract class Node { flags: CommonFlags, range: Range ): MethodDeclaration { - var stmt = new MethodDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.signature = signature; - stmt.body = body; - stmt.decorators = decorators; - return stmt; + var node = new MethodDeclaration(); + node.kind = NodeKind.METHODDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.signature = signature; + node.body = body; + node.decorators = decorators; + return node; } static createNamespaceDeclaration( @@ -913,23 +983,25 @@ export abstract class Node { flags: CommonFlags, range: Range ): NamespaceDeclaration { - var stmt = new NamespaceDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.members = members; - stmt.decorators = decorators; - return stmt; + var node = new NamespaceDeclaration(); + node.kind = NodeKind.NAMESPACEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.members = members; + node.decorators = decorators; + return node; } static createReturnStatement( value: Expression | null, range: Range ): ReturnStatement { - var stmt = new ReturnStatement(); - stmt.range = range; - stmt.value = value; - return stmt; + var node = new ReturnStatement(); + node.kind = NodeKind.RETURN; + node.range = range; + node.value = value; + return node; } static createSwitchStatement( @@ -937,11 +1009,12 @@ export abstract class Node { cases: SwitchCase[], range: Range ): SwitchStatement { - var stmt = new SwitchStatement(); - stmt.range = range; - stmt.condition = condition; - stmt.cases = cases; - return stmt; + var node = new SwitchStatement(); + node.kind = NodeKind.SWITCH; + node.range = range; + node.condition = condition; + node.cases = cases; + return node; } static createSwitchCase( @@ -949,21 +1022,23 @@ export abstract class Node { statements: Statement[], range: Range ): SwitchCase { - var elem = new SwitchCase(); - elem.range = range; - elem.label = label; - elem.statements = statements; - return elem; + var node = new SwitchCase(); + node.kind = NodeKind.SWITCHCASE; + node.range = range; + node.label = label; + node.statements = statements; + return node; } static createThrowStatement( value: Expression, range: Range ): ThrowStatement { - var stmt = new ThrowStatement(); - stmt.range = range; - stmt.value = value; - return stmt; + var node = new ThrowStatement(); + node.kind = NodeKind.THROW; + node.range = range; + node.value = value; + return node; } static createTryStatement( @@ -973,13 +1048,14 @@ export abstract class Node { finallyStatements: Statement[] | null, range: Range ): TryStatement { - var stmt = new TryStatement(); - stmt.range = range; - stmt.statements = statements; - stmt.catchVariable = catchVariable; - stmt.catchStatements = catchStatements; - stmt.finallyStatements = finallyStatements; - return stmt; + var node = new TryStatement(); + node.kind = NodeKind.TRY; + node.range = range; + node.statements = statements; + node.catchVariable = catchVariable; + node.catchStatements = catchStatements; + node.finallyStatements = finallyStatements; + return node; } static createTypeDeclaration( @@ -990,14 +1066,15 @@ export abstract class Node { flags: CommonFlags, range: Range ): TypeDeclaration { - var stmt = new TypeDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.type = alias; - stmt.decorators = decorators; - return stmt; + var node = new TypeDeclaration(); + node.kind = NodeKind.TYPEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.type = alias; + node.decorators = decorators; + return node; } static createVariableStatement( @@ -1005,11 +1082,12 @@ export abstract class Node { decorators: DecoratorNode[] | null, range: Range ): VariableStatement { - var stmt = new VariableStatement(); - stmt.range = range; - stmt.declarations = declarations; - stmt.decorators = decorators; - return stmt; + var node = new VariableStatement(); + node.kind = NodeKind.VARIABLE; + node.range = range; + node.declarations = declarations; + node.decorators = decorators; + return node; } static createVariableDeclaration( @@ -1020,24 +1098,26 @@ export abstract class Node { flags: CommonFlags, range: Range ): VariableDeclaration { - var elem = new VariableDeclaration(); - elem.range = range; - elem.flags = flags; - elem.name = name; - elem.type = type; - elem.initializer = initializer; - elem.decorators = decorators; // inherited - return elem; + var node = new VariableDeclaration(); + node.kind = NodeKind.VARIABLEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.type = type; + node.initializer = initializer; + node.decorators = decorators; // inherited + return node; } static createVoidStatement( expression: Expression, range: Range ): VoidStatement { - var stmt = new VoidStatement(); - stmt.range = range; - stmt.expression = expression; - return stmt; + var node = new VoidStatement(); + node.kind = NodeKind.VOID; + node.range = range; + node.expression = expression; + return node; } static createWhileStatement( @@ -1045,11 +1125,12 @@ export abstract class Node { statement: Statement, range: Range ): WhileStatement { - var stmt = new WhileStatement(); - stmt.range = range; - stmt.condition = condition; - stmt.statement = statement; - return stmt; + var node = new WhileStatement(); + node.kind = NodeKind.WHILE; + node.range = range; + node.condition = condition; + node.statement = statement; + return node; } } @@ -1095,8 +1176,6 @@ export abstract class TypeNode extends Node { /** Represents a type name. */ export class TypeName extends Node { - kind = NodeKind.TYPENAME; - /** Identifier of this part. */ identifier: IdentifierExpression; /** Next part of the type name or `null` if this is the last part. */ @@ -1105,8 +1184,6 @@ export class TypeName extends Node { /** Represents a named type. */ export class NamedTypeNode extends TypeNode { - kind = NodeKind.NAMEDTYPE; - /** Type name. */ name: TypeName; /** Type argument references. */ @@ -1120,8 +1197,6 @@ export class NamedTypeNode extends TypeNode { /** Represents a function type. */ export class FunctionTypeNode extends TypeNode { - kind = NodeKind.FUNCTIONTYPE; - /** Accepted parameters. */ parameters: ParameterNode[]; /** Return type. */ @@ -1132,8 +1207,6 @@ export class FunctionTypeNode extends TypeNode { /** Represents a type parameter. */ export class TypeParameterNode extends Node { - kind = NodeKind.TYPEPARAMETER; - /** Identifier reference. */ name: IdentifierExpression; /** Extended type reference, if any. */ @@ -1154,8 +1227,6 @@ export enum ParameterKind { /** Represents a function parameter. */ export class ParameterNode extends Node { - kind = NodeKind.PARAMETER; - /** Parameter kind. */ parameterKind: ParameterKind; /** Parameter name. */ @@ -1270,8 +1341,6 @@ export namespace DecoratorKind { /** Represents a decorator. */ export class DecoratorNode extends Node { - kind = NodeKind.DECORATOR; - /** Built-in kind, if applicable. */ decoratorKind: DecoratorKind; /** Name expression. */ @@ -1292,8 +1361,6 @@ export enum CommentKind { /** Represents a comment. */ export class CommentNode extends Node { - kind = NodeKind.COMMENT; - /** Comment kind. */ commentKind: CommentKind; /** Comment text. */ @@ -1307,8 +1374,6 @@ export abstract class Expression extends Node { } /** Represents an identifier expression. */ export class IdentifierExpression extends Expression { - kind = NodeKind.IDENTIFIER; - /** Textual name. */ text: string; /** Whether quoted or not. */ @@ -1338,16 +1403,12 @@ export function isNumericLiteral(node: Expression): bool { /** Base class of all literal expressions. */ export abstract class LiteralExpression extends Expression { - kind = NodeKind.LITERAL; - /** Specific literal kind. */ literalKind: LiteralKind; } /** Represents an `[]` literal expression. */ export class ArrayLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.ARRAY; - /** Nested element expressions. */ elementExpressions: (Expression | null)[]; } @@ -1362,8 +1423,6 @@ export enum AssertionKind { /** Represents an assertion expression. */ export class AssertionExpression extends Expression { - kind = NodeKind.ASSERTION; - /** Specific kind of this assertion. */ assertionKind: AssertionKind; /** Expression being asserted. */ @@ -1374,8 +1433,6 @@ export class AssertionExpression extends Expression { /** Represents a binary expression. */ export class BinaryExpression extends Expression { - kind = NodeKind.BINARY; - /** Operator token. */ operator: Token; /** Left-hand side expression */ @@ -1386,8 +1443,6 @@ export class BinaryExpression extends Expression { /** Represents a call expression. */ export class CallExpression extends Expression { - kind = NodeKind.CALL; - /** Called expression. Usually an identifier or property access expression. */ expression: Expression; /** Provided type arguments. */ @@ -1418,30 +1473,22 @@ export class CallExpression extends Expression { /** Represents a class expression using the 'class' keyword. */ export class ClassExpression extends Expression { - kind = NodeKind.CLASS; - /** Inline class declaration. */ declaration: ClassDeclaration; } /** Represents a comma expression composed of multiple expressions. */ export class CommaExpression extends Expression { - kind = NodeKind.COMMA; - /** Sequential expressions. */ expressions: Expression[]; } /** Represents a `constructor` expression. */ export class ConstructorExpression extends IdentifierExpression { - kind = NodeKind.CONSTRUCTOR; - text = "constructor"; } /** Represents an element access expression, e.g., array access. */ export class ElementAccessExpression extends Expression { - kind = NodeKind.ELEMENTACCESS; - /** Expression being accessed. */ expression: Expression; /** Element of the expression being accessed. */ @@ -1450,24 +1497,18 @@ export class ElementAccessExpression extends Expression { /** Represents a float literal expression. */ export class FloatLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.FLOAT; - /** Float value. */ value: f64; } /** Represents a function expression using the 'function' keyword. */ export class FunctionExpression extends Expression { - kind = NodeKind.FUNCTION; - /** Inline function declaration. */ declaration: FunctionDeclaration; } /** Represents an `instanceof` expression. */ export class InstanceOfExpression extends Expression { - kind = NodeKind.INSTANCEOF; - /** Expression being asserted. */ expression: Expression; /** Type to test for. */ @@ -1476,16 +1517,12 @@ export class InstanceOfExpression extends Expression { /** Represents an integer literal expression. */ export class IntegerLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.INTEGER; - /** Integer value. */ value: I64; } /** Represents a `new` expression. Like a call but with its own kind. */ export class NewExpression extends Expression { - kind = NodeKind.NEW; - /** Type being constructed. */ typeName: TypeName; /** Provided type arguments. */ @@ -1516,14 +1553,10 @@ export class NewExpression extends Expression { /** Represents a `null` expression. */ export class NullExpression extends IdentifierExpression { - kind = NodeKind.NULL; - text = "null"; } /** Represents an object literal expression. */ export class ObjectLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.OBJECT; - /** Field names. */ names: IdentifierExpression[]; /** Field values. */ @@ -1532,16 +1565,12 @@ export class ObjectLiteralExpression extends LiteralExpression { /** Represents a parenthesized expression. */ export class ParenthesizedExpression extends Expression { - kind = NodeKind.PARENTHESIZED; - /** Expression in parenthesis. */ expression: Expression; } /** Represents a property access expression. */ export class PropertyAccessExpression extends Expression { - kind = NodeKind.PROPERTYACCESS; - /** Expression being accessed. */ expression: Expression; /** Property of the expression being accessed. */ @@ -1550,8 +1579,6 @@ export class PropertyAccessExpression extends Expression { /** Represents a regular expression literal expression. */ export class RegexpLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.REGEXP; - /** Regular expression pattern. */ pattern: string; /** Regular expression flags. */ @@ -1560,8 +1587,6 @@ export class RegexpLiteralExpression extends LiteralExpression { /** Represents a ternary expression, i.e., short if notation. */ export class TernaryExpression extends Expression { - kind = NodeKind.TERNARY; - /** Condition expression. */ condition: Expression; /** Expression executed when condition is `true`. */ @@ -1572,39 +1597,28 @@ export class TernaryExpression extends Expression { /** Represents a string literal expression. */ export class StringLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.STRING; - /** String value without quotes. */ value: string; } /** Represents a `super` expression. */ export class SuperExpression extends IdentifierExpression { - kind = NodeKind.SUPER; - text = "super"; } /** Represents a `this` expression. */ export class ThisExpression extends IdentifierExpression { - kind = NodeKind.THIS; - text = "this"; } /** Represents a `true` expression. */ export class TrueExpression extends IdentifierExpression { - kind = NodeKind.TRUE; - text = "true"; } /** Represents a `false` expression. */ export class FalseExpression extends IdentifierExpression { - kind = NodeKind.FALSE; - text = "false"; } /** Base class of all unary expressions. */ export abstract class UnaryExpression extends Expression { - /** Operator token. */ operator: Token; /** Operand expression. */ @@ -1613,12 +1627,10 @@ export abstract class UnaryExpression extends Expression { /** Represents a unary postfix expression, e.g. a postfix increment. */ export class UnaryPostfixExpression extends UnaryExpression { - kind = NodeKind.UNARYPOSTFIX; } /** Represents a unary prefix expression, e.g. a negation. */ export class UnaryPrefixExpression extends UnaryExpression { - kind = NodeKind.UNARYPREFIX; } // statements @@ -1640,9 +1652,6 @@ export enum SourceKind { /** A top-level source node. */ export class Source extends Node { - kind = NodeKind.SOURCE; - parent = null; - /** Source kind. */ sourceKind: SourceKind; /** Normalized path with file extension. */ @@ -1663,6 +1672,7 @@ export class Source extends Node { /** Constructs a new source node. */ constructor(normalizedPath: string, text: string, kind: SourceKind) { super(); + this.kind = NodeKind.SOURCE; this.sourceKind = kind; this.normalizedPath = normalizedPath; var internalPath = mangleInternalPath(this.normalizedPath); @@ -1705,8 +1715,6 @@ export abstract class DeclarationStatement extends Statement { /** Represents an index signature declaration. */ export class IndexSignatureDeclaration extends DeclarationStatement { - kind = NodeKind.INDEXSIGNATUREDECLARATION; - /** Key type. */ keyType: NamedTypeNode; /** Value type. */ @@ -1715,7 +1723,6 @@ export class IndexSignatureDeclaration extends DeclarationStatement { /** Base class of all variable-like declaration statements. */ export abstract class VariableLikeDeclarationStatement extends DeclarationStatement { - /** Variable type. */ type: TypeNode | null; /** Variable initializer. */ @@ -1724,24 +1731,18 @@ export abstract class VariableLikeDeclarationStatement extends DeclarationStatem /** Represents a block statement. */ export class BlockStatement extends Statement { - kind = NodeKind.BLOCK; - /** Contained statements. */ statements: Statement[]; } /** Represents a `break` statement. */ export class BreakStatement extends Statement { - kind = NodeKind.BREAK; - /** Target label, if applicable. */ label: IdentifierExpression | null; } /** Represents a `class` declaration. */ export class ClassDeclaration extends DeclarationStatement { - kind = NodeKind.CLASSDECLARATION; - /** Accepted type parameters. */ typeParameters: TypeParameterNode[] | null; /** Base class type being extended, if any. */ @@ -1759,16 +1760,12 @@ export class ClassDeclaration extends DeclarationStatement { /** Represents a `continue` statement. */ export class ContinueStatement extends Statement { - kind = NodeKind.CONTINUE; - /** Target label, if applicable. */ label: IdentifierExpression | null; } /** Represents a `do` statement. */ export class DoStatement extends Statement { - kind = NodeKind.DO; - /** Statement being looped over. */ statement: Statement; /** Condition when to repeat. */ @@ -1777,30 +1774,22 @@ export class DoStatement extends Statement { /** Represents an empty statement, i.e., a semicolon terminating nothing. */ export class EmptyStatement extends Statement { - kind = NodeKind.EMPTY; } /** Represents an `enum` declaration. */ export class EnumDeclaration extends DeclarationStatement { - kind = NodeKind.ENUMDECLARATION; - /** Enum value declarations. */ values: EnumValueDeclaration[]; } /** Represents a value of an `enum` declaration. */ export class EnumValueDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.ENUMVALUEDECLARATION; - // name is inherited - /** Value expression. */ value: Expression | null; } /** Represents an `export import` statement of an interface. */ export class ExportImportStatement extends Node { - kind = NodeKind.EXPORTIMPORT; - /** Identifier being imported. */ name: IdentifierExpression; /** Identifier being exported. */ @@ -1809,8 +1798,6 @@ export class ExportImportStatement extends Node { /** Represents a member of an `export` statement. */ export class ExportMember extends Node { - kind = NodeKind.EXPORTMEMBER; - /** Local identifier. */ localName: IdentifierExpression; /** Exported identifier. */ @@ -1819,8 +1806,6 @@ export class ExportMember extends Node { /** Represents an `export` statement. */ export class ExportStatement extends Statement { - kind = NodeKind.EXPORT; - /** Array of members if a set of named exports, or `null` if a file export. */ members: ExportMember[] | null; /** Path being exported from, if applicable. */ @@ -1833,32 +1818,24 @@ export class ExportStatement extends Statement { /** Represents an `export default` statement. */ export class ExportDefaultStatement extends Statement { - kind = NodeKind.EXPORTDEFAULT; - /** Declaration being exported as default. */ declaration: DeclarationStatement; } /** Represents an expression that is used as a statement. */ export class ExpressionStatement extends Statement { - kind = NodeKind.EXPRESSION; - /** Expression being used as a statement.*/ expression: Expression; } /** Represents a field declaration within a `class`. */ export class FieldDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.FIELDDECLARATION; - /** Parameter index if declared as a constructor parameter, otherwise `-1`. */ parameterIndex: i32 = -1; } /** Represents a `for` statement. */ export class ForStatement extends Statement { - kind = NodeKind.FOR; - /** Initializer statement, if present. Either a `VariableStatement` or `ExpressionStatement`. */ initializer: Statement | null; /** Condition expression, if present. */ @@ -1871,8 +1848,6 @@ export class ForStatement extends Statement { /** Represents a `for..of` statement. */ export class ForOfStatement extends Statement { - kind = NodeKind.FOROF; - /** Variable statement. Either a `VariableStatement` or `ExpressionStatement` of `IdentifierExpression`. */ variable: Statement; /** Iterable expression being iterated. */ @@ -1893,8 +1868,6 @@ export const enum ArrowKind { /** Represents a `function` declaration. */ export class FunctionDeclaration extends DeclarationStatement { - kind = NodeKind.FUNCTIONDECLARATION; - /** Type parameters, if any. */ typeParameters: TypeParameterNode[] | null; /** Function signature. */ @@ -1926,8 +1899,6 @@ export class FunctionDeclaration extends DeclarationStatement { /** Represents an `if` statement. */ export class IfStatement extends Statement { - kind = NodeKind.IF; - /** Condition. */ condition: Expression; /** Statement executed when condition is `true`. */ @@ -1938,16 +1909,12 @@ export class IfStatement extends Statement { /** Represents an `import` declaration part of an {@link ImportStatement}. */ export class ImportDeclaration extends DeclarationStatement { - kind = NodeKind.IMPORTDECLARATION; - /** Identifier being imported. */ foreignName: IdentifierExpression; } /** Represents an `import` statement. */ export class ImportStatement extends Statement { - kind = NodeKind.IMPORT; - /** Array of member declarations or `null` if an asterisk import. */ declarations: ImportDeclaration[] | null; /** Name of the local namespace, if an asterisk import. */ @@ -1960,34 +1927,26 @@ export class ImportStatement extends Statement { /** Represents an `interfarce` declaration. */ export class InterfaceDeclaration extends ClassDeclaration { - kind = NodeKind.INTERFACEDECLARATION; } /** Represents a method declaration within a `class`. */ export class MethodDeclaration extends FunctionDeclaration { - kind = NodeKind.METHODDECLARATION; } /** Represents a `namespace` declaration. */ export class NamespaceDeclaration extends DeclarationStatement { - kind = NodeKind.NAMESPACEDECLARATION; - /** Array of namespace members. */ members: Statement[]; } /** Represents a `return` statement. */ export class ReturnStatement extends Statement { - kind = NodeKind.RETURN; - /** Value expression being returned, if present. */ value: Expression | null; } /** Represents a single `case` within a `switch` statement. */ export class SwitchCase extends Node { - kind = NodeKind.SWITCHCASE; - /** Label expression. `null` indicates the default case. */ label: Expression | null; /** Contained statements. */ @@ -1996,8 +1955,6 @@ export class SwitchCase extends Node { /** Represents a `switch` statement. */ export class SwitchStatement extends Statement { - kind = NodeKind.SWITCH; - /** Condition expression. */ condition: Expression; /** Contained cases. */ @@ -2006,16 +1963,12 @@ export class SwitchStatement extends Statement { /** Represents a `throw` statement. */ export class ThrowStatement extends Statement { - kind = NodeKind.THROW; - /** Value expression being thrown. */ value: Expression; } /** Represents a `try` statement. */ export class TryStatement extends Statement { - kind = NodeKind.TRY; - /** Contained statements. */ statements: Statement[]; /** Exception variable name, if a `catch` clause is present. */ @@ -2028,8 +1981,6 @@ export class TryStatement extends Statement { /** Represents a `type` declaration. */ export class TypeDeclaration extends DeclarationStatement { - kind = NodeKind.TYPEDECLARATION; - /** Type parameters, if any. */ typeParameters: TypeParameterNode[] | null; /** Type being aliased. */ @@ -2038,13 +1989,10 @@ export class TypeDeclaration extends DeclarationStatement { /** Represents a variable declaration part of a {@link VariableStatement}. */ export class VariableDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.VARIABLEDECLARATION; } /** Represents a variable statement wrapping {@link VariableDeclaration}s. */ export class VariableStatement extends Statement { - kind = NodeKind.VARIABLE; - /** Array of decorators. */ decorators: DecoratorNode[] | null; /** Array of member declarations. */ @@ -2053,16 +2001,12 @@ export class VariableStatement extends Statement { /** Represents a void statement dropping an expression's value. */ export class VoidStatement extends Statement { - kind = NodeKind.VOID; - /** Expression being dropped. */ expression: Expression; } /** Represents a `while` statement. */ export class WhileStatement extends Statement { - kind = NodeKind.WHILE; - /** Condition expression. */ condition: Expression; /** Statement being looped over. */ From 74abb84ba3c3c5e9688b3cefc0f549471390315e Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 28 Feb 2020 02:16:45 +0100 Subject: [PATCH 05/28] fix reported sourcePath of portable d.ts --- cli/asc.js | 5 +++-- src/glue/wasm/index.ts | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/asc.js b/cli/asc.js index c88ec45bd3..c64977a0ef 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -390,7 +390,8 @@ exports.main = function main(argv, options, callback) { if ((sourceText = readFile(sourcePath = internalPath + ".ts", baseDir)) == null) { if ((sourceText = readFile(sourcePath = internalPath + "/index.ts", baseDir)) == null) { // portable d.ts: uses the .js file next to it in JS or becomes an import in Wasm - sourceText = readFile(sourcePath = internalPath + ".d.ts", baseDir); + sourcePath = internalPath + ".ts"; + sourceText = readFile(internalPath + ".d.ts", baseDir); } } @@ -478,7 +479,7 @@ exports.main = function main(argv, options, callback) { var internalPath; while ((internalPath = assemblyscript.nextFile(program)) != null) { let file = getFile(internalPath, assemblyscript.getDependee(program, internalPath)); - if (!file) return callback(Error("Import file '" + internalPath + ".ts' not found.")) + if (!file) return callback(Error("Import '" + internalPath + "' not found.")) stats.parseCount++; stats.parseTime += measure(() => { assemblyscript.parse(program, file.sourceText, file.sourcePath, false); diff --git a/src/glue/wasm/index.ts b/src/glue/wasm/index.ts index 68e707ff4f..6652e0047d 100644 --- a/src/glue/wasm/index.ts +++ b/src/glue/wasm/index.ts @@ -4,7 +4,6 @@ * @preferred *//***/ -import "../binaryen.d"; import "./i64"; import "./float"; import "./mapset"; From fb623c67e85e3100e775d7c5c7a3592d8c2b48be Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 28 Feb 2020 03:08:22 +0100 Subject: [PATCH 06/28] fixed 145 compile errors, down to 894 --- cli/asc.js | 16 +++++--- src/ast.ts | 6 +-- src/builtins.ts | 10 ++--- src/compiler.ts | 87 ++++++++++++++++++++++++++++++------------ src/definitions.ts | 4 +- src/diagnostics.ts | 23 ++++++----- src/extra/ast.ts | 2 +- src/flow.ts | 6 +-- src/glue/js/float.d.ts | 4 +- src/glue/js/i64.d.ts | 84 ++++++++++++++++++++-------------------- src/glue/js/i64.js | 2 +- src/glue/wasm/i64.ts | 70 +++++++++++++++++---------------- src/index.ts | 16 ++++---- src/module.ts | 33 ++++++++-------- src/program.ts | 13 ++++--- src/resolver.ts | 21 +++++----- src/tokenizer.ts | 10 ++--- src/types.ts | 2 +- src/util/binary.ts | 4 +- src/util/bitset.ts | 4 +- 20 files changed, 231 insertions(+), 186 deletions(-) diff --git a/cli/asc.js b/cli/asc.js index c64977a0ef..7832b2ba32 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -485,7 +485,10 @@ exports.main = function main(argv, options, callback) { assemblyscript.parse(program, file.sourceText, file.sourcePath, false); }); } - if (checkDiagnostics(program, stderr)) return callback(Error("Parse error")); + var numErrors = checkDiagnostics(program, stderr); + if (numErrors) { + return callback(Error(numErrors + " parse error(s)")); + } } // Include runtime template before entry files so its setup runs first @@ -580,9 +583,10 @@ exports.main = function main(argv, options, callback) { } catch (e) { return callback(e); } - if (checkDiagnostics(program, stderr)) { + var numErrors = checkDiagnostics(program, stderr); + if (numErrors) { if (module) module.dispose(); - return callback(Error("Compile error")); + return callback(Error(numErrors + " compile error(s)")); } // Call afterCompile transform hook @@ -1024,7 +1028,7 @@ exports.main = function main(argv, options, callback) { /** Checks diagnostics emitted so far for errors. */ function checkDiagnostics(program, stderr) { var diagnostic; - var hasErrors = false; + var numErrors = 0; while ((diagnostic = assemblyscript.nextDiagnostic(program)) != null) { if (stderr) { stderr.write( @@ -1032,9 +1036,9 @@ function checkDiagnostics(program, stderr) { EOL + EOL ); } - if (assemblyscript.isError(diagnostic)) hasErrors = true; + if (assemblyscript.isError(diagnostic)) ++numErrors; } - return hasErrors; + return numErrors; } exports.checkDiagnostics = checkDiagnostics; diff --git a/src/ast.ts b/src/ast.ts index 06dff06ffd..bb6ec1e716 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -21,8 +21,6 @@ import { CharCode } from "./util"; -export { Token, Range }; - /** Indicates the kind of a node. */ export enum NodeKind { @@ -417,7 +415,7 @@ export abstract class Node { } static createIntegerLiteralExpression( - value: I64, + value: i64, range: Range ): IntegerLiteralExpression { var node = new IntegerLiteralExpression(); @@ -1518,7 +1516,7 @@ export class InstanceOfExpression extends Expression { /** Represents an integer literal expression. */ export class IntegerLiteralExpression extends LiteralExpression { /** Integer value. */ - value: I64; + value: i64; } /** Represents a `new` expression. Like a call but with its own kind. */ diff --git a/src/builtins.ts b/src/builtins.ts index 7622b1440e..ab6bfb81c8 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -5007,7 +5007,7 @@ function evaluateConstantType( if (!typeArguments || typeArguments.length != 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments ? typeArguments.length.toString(10) : "0" + reportNode.typeArgumentsRange, "1", typeArguments ? typeArguments.length.toString() : "0" ); return null; } @@ -5018,7 +5018,7 @@ function evaluateConstantType( if (typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString(10) + reportNode.typeArgumentsRange, "1", typeArguments.length.toString() ); return null; } @@ -5031,12 +5031,12 @@ function evaluateConstantType( if (typeArguments && typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString(10) + reportNode.typeArgumentsRange, "1", typeArguments.length.toString() ); } compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.argumentsRange, "1", operands.length.toString(10) + reportNode.argumentsRange, "1", operands.length.toString() ); return null; } @@ -5197,7 +5197,7 @@ function checkArgsOptional( } /** Makes an usize constant matching contextual type if reasonable. */ -function contextualUsize(compiler: Compiler, value: I64, contextualType: Type): ExpressionRef { +function contextualUsize(compiler: Compiler, value: i64, contextualType: Type): ExpressionRef { var module = compiler.module; // Check if contextual type fits if (contextualType != Type.auto && contextualType.is(TypeFlags.INTEGER | TypeFlags.VALUE)) { diff --git a/src/compiler.ts b/src/compiler.ts index c11a93e06b..a82056ace1 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -101,13 +101,13 @@ import { import { Token, + Range, operatorTokenToString } from "./tokenizer"; import { Node, NodeKind, - Range, DecoratorKind, AssertionKind, SourceKind, @@ -322,7 +322,7 @@ export class Compiler extends DiagnosticEmitter { /** Start function statements. */ currentBody: ExpressionRef[]; /** Counting memory offset. */ - memoryOffset: I64; + memoryOffset: i64; /** Memory segments being compiled. */ memorySegments: MemorySegment[] = []; /** Map of already compiled static string segments. */ @@ -399,7 +399,9 @@ export class Compiler extends DiagnosticEmitter { // compile entry file(s) while traversing reachable elements var files = program.filesByName; - for (let file of files.values()) { + // for (let file of files.values()) { + for (let _values = Map_values(files), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) { this.compileFile(file); this.compileExports(file); @@ -437,7 +439,9 @@ export class Compiler extends DiagnosticEmitter { var cyclicClasses = program.findCyclicClasses(); if (cyclicClasses.size) { if (options.pedantic) { - for (let classInstance of cyclicClasses) { + // for (let classInstance of cyclicClasses) { + for (let _values = Set_values(cyclicClasses), i = 0, k = _values.length; i < k; ++i) { + let classInstance = unchecked(_values[i]); this.pedantic( DiagnosticCode.Type_0_is_cyclic_Module_will_include_deferred_garbage_collection, classInstance.identifierNode.range, classInstance.internalName @@ -452,7 +456,9 @@ export class Compiler extends DiagnosticEmitter { var lazyLibraryFunctions = this.lazyLibraryFunctions; do { let functionsToCompile = new Array(); - for (let instance of lazyLibraryFunctions) { + // for (let instance of lazyLibraryFunctions) { + for (let _values = Set_values(lazyLibraryFunctions), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); functionsToCompile.push(instance); } lazyLibraryFunctions.clear(); @@ -462,7 +468,9 @@ export class Compiler extends DiagnosticEmitter { } while (lazyLibraryFunctions.size); // compile pending class-specific instanceof helpers - for (let prototype of this.pendingClassInstanceOf.values()) { + // for (let prototype of this.pendingClassInstanceOf.values()) { + for (let _values = Set_values(this.pendingClassInstanceOf), i = 0, k = _values.length; i < k; ++i) { + let prototype = unchecked(_values[i]); compileClassInstanceOf(this, prototype); } @@ -538,7 +546,9 @@ export class Compiler extends DiagnosticEmitter { } // set up module exports - for (let file of this.program.filesByName.values()) { + // for (let file of this.program.filesByName.values()) { + for (let _values = Map_values(this.program.filesByName), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) this.ensureModuleExports(file); } return module; @@ -571,7 +581,9 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.FUNCTION_PROTOTYPE: { let instances = (element).instances; if (instances) { - for (let instance of instances.values()) { + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); let instanceName = name; if (instance.is(CommonFlags.GENERIC)) { let fullName = instance.internalName; @@ -585,7 +597,9 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.CLASS_PROTOTYPE: { let instances = (element).instances; if (instances) { - for (let instance of instances.values()) { + // for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); let instanceName = name; if (instance.is(CommonFlags.GENERIC)) { let fullName = instance.internalName; @@ -688,12 +702,16 @@ export class Compiler extends DiagnosticEmitter { element.kind == ElementKind.NAMESPACE || element.kind == ElementKind.FILE ) { - for (let member of members.values()) { + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (!member.is(CommonFlags.EXPORT)) continue; this.ensureModuleExport(member.name, member, subPrefix); } } else { - for (let member of members.values()) { + // for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.is(CommonFlags.PRIVATE)) continue; this.ensureModuleExport(member.name, member, subPrefix); } @@ -751,17 +769,30 @@ export class Compiler extends DiagnosticEmitter { } if (compileMembers) { let members = element.members; - if (members) for (let element of members.values()) this.compileElement(element); + if (members) { + // for (let element of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); + this.compileElement(element); + } + } } } /** Compiles a file's exports. */ compileExports(file: File): void { var exports = file.exports; - if (exports) for (let element of exports.values()) this.compileElement(element); - var exportsStar = file.exportsStar; - if (exportsStar) { - for (let exportStar of exportsStar) { + if (exports) { + // for (let element of exports.values()) { + for (let _values = Map_values(exports), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); + this.compileElement(element); + } + } + var starExports = file.exportsStar; + if (starExports) { + for (let i = 0, k = starExports.length; i < k; ++i) { + let exportStar = unchecked(starExports[i]); this.compileFile(exportStar); this.compileExports(exportStar); } @@ -1056,7 +1087,9 @@ export class Compiler extends DiagnosticEmitter { var isInline = element.is(CommonFlags.CONST) || element.hasDecorator(DecoratorFlags.INLINE); if (element.members) { - for (let member of element.members.values()) { + // for (let member of element.members.values()) { + for (let _values = Map_values(element.members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) continue; // happens if an enum is also a namespace let initInStart = false; let val = member; @@ -1374,7 +1407,9 @@ export class Compiler extends DiagnosticEmitter { var prototype = instance.prototype; var staticMembers = (prototype).members; if (staticMembers) { - for (let element of staticMembers.values()) { + // for (let element of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); switch (element.kind) { case ElementKind.GLOBAL: { this.compileGlobal(element); @@ -1409,7 +1444,9 @@ export class Compiler extends DiagnosticEmitter { if (ctorInstance) this.compileFunction(ctorInstance); var instanceMembers = instance.members; if (instanceMembers) { - for (let element of instanceMembers.values()) { + // for (let element of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); switch (element.kind) { case ElementKind.FUNCTION_PROTOTYPE: { if (!element.is(CommonFlags.GENERIC)) { @@ -2572,7 +2609,7 @@ export class Compiler extends DiagnosticEmitter { let case_ = cases[i]; let label = case_.label; if (label) { - breaks[breakIndex++] = module.br("case" + i.toString(10) + "|" + context, + breaks[breakIndex++] = module.br("case" + i.toString() + "|" + context, module.binary(BinaryOp.EqI32, module.local_get(tempLocalIndex, NativeType.I32), this.compileExpression(label, Type.u32, @@ -2589,7 +2626,7 @@ export class Compiler extends DiagnosticEmitter { // otherwise br to default respectively out of the switch if there is no default case breaks[breakIndex] = module.br((defaultIndex >= 0 - ? "case" + defaultIndex.toString(10) + ? "case" + defaultIndex.toString() : "break" ) + "|" + context); @@ -2609,7 +2646,7 @@ export class Compiler extends DiagnosticEmitter { innerFlow.breakLabel = breakLabel; let isLast = i == numCases - 1; - let nextLabel = isLast ? breakLabel : "case" + (i + 1).toString(10) + "|" + context; + let nextLabel = isLast ? breakLabel : "case" + (i + 1).toString() + "|" + context; let stmts = new Array(1 + numStatements); stmts[0] = currentBlock; let count = 1; @@ -6683,9 +6720,9 @@ export class Compiler extends DiagnosticEmitter { // create a br_table switching over the number of optional parameters provided var numNames = numOptional + 1; // incl. outer block var names = new Array(numNames); - var ofN = "of" + numOptional.toString(10); + var ofN = "of" + numOptional.toString(); for (let i = 0; i < numNames; ++i) { - let label = i.toString(10) + ofN; + let label = i.toString() + ofN; names[i] = label; } var body = module.block(names[0], [ @@ -7379,7 +7416,7 @@ export class Compiler extends DiagnosticEmitter { var prototype = new FunctionPrototype( declaration.name.text.length ? declaration.name.text - : "anonymous|" + (actualFunction.nextAnonymousId++).toString(10), + : "anonymous|" + (actualFunction.nextAnonymousId++).toString(), actualFunction, declaration, DecoratorFlags.NONE diff --git a/src/definitions.ts b/src/definitions.ts index 8bd3fcf8c7..bf537cdbef 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -243,7 +243,7 @@ export class IDLBuilder extends ExportsWalker { if (isConst) { sb.push(" = "); assert(value.constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low(value.constantIntegerValue).toString(10)); + sb.push(i64_low(value.constantIntegerValue).toString()); } sb.push(";\n"); } @@ -425,7 +425,7 @@ export class TSDBuilder extends ExportsWalker { if (member.is(CommonFlags.INLINED)) { sb.push(" = "); assert(value.constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low(value.constantIntegerValue).toString(10)); + sb.push(i64_low(value.constantIntegerValue).toString()); } sb.push(",\n"); --remainingMembers; diff --git a/src/diagnostics.ts b/src/diagnostics.ts index 36df68a519..2cf3927cde 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -5,7 +5,10 @@ *//***/ import { - Range, + Range +} from "./tokenizer"; + +import { Source } from "./ast"; @@ -128,21 +131,21 @@ export class DiagnosticMessage { return ( diagnosticCategoryToString(this.category) + " " + - this.code.toString(10) + + this.code.toString() + ": \"" + this.message + "\" in " + this.range.source.normalizedPath + ":" + - this.range.line.toString(10) + + this.range.line.toString() + ":" + - this.range.column.toString(10) + this.range.column.toString() ); } return ( diagnosticCategoryToString(this.category) + " " + - this.code.toString(10) + + this.code.toString() + ": " + this.message ); @@ -162,7 +165,7 @@ export function formatDiagnosticMessage( sb.push(diagnosticCategoryToString(message.category)); if (useColors) sb.push(COLOR_RESET); sb.push(message.code < 1000 ? " AS" : " TS"); - sb.push(message.code.toString(10)); + sb.push(message.code.toString()); sb.push(": "); sb.push(message.message); @@ -179,9 +182,9 @@ export function formatDiagnosticMessage( sb.push(" in "); sb.push(range.source.normalizedPath); sb.push("("); - sb.push(range.line.toString(10)); + sb.push(range.line.toString()); sb.push(","); - sb.push(range.column.toString(10)); + sb.push(range.column.toString()); sb.push(")"); let relatedRange = message.relatedRange; @@ -194,9 +197,9 @@ export function formatDiagnosticMessage( sb.push(" in "); sb.push(relatedRange.source.normalizedPath); sb.push("("); - sb.push(relatedRange.line.toString(10)); + sb.push(relatedRange.line.toString()); sb.push(","); - sb.push(relatedRange.column.toString(10)); + sb.push(relatedRange.column.toString()); sb.push(")"); } } diff --git a/src/extra/ast.ts b/src/extra/ast.ts index 946aab1a01..e3c4300542 100644 --- a/src/extra/ast.ts +++ b/src/extra/ast.ts @@ -656,7 +656,7 @@ export class ASTBuilder { } visitFloatLiteralExpression(node: FloatLiteralExpression): void { - this.sb.push(node.value.toString(10)); + this.sb.push(node.value.toString()); } visitInstanceOfExpression(node: InstanceOfExpression): void { diff --git a/src/flow.ts b/src/flow.ts index ac1bbc512d..98c60cf888 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -213,7 +213,7 @@ export class Flow { static createInline(parentFunction: Function, inlineFunction: Function): Flow { var flow = Flow.create(parentFunction); flow.inlineFunction = inlineFunction; - flow.inlineReturnLabel = inlineFunction.internalName + "|inlined." + (inlineFunction.nextInlineId++).toString(10); + flow.inlineReturnLabel = inlineFunction.internalName + "|inlined." + (inlineFunction.nextInlineId++).toString(); flow.returnType = inlineFunction.signature.returnType; flow.contextualTypeArguments = inlineFunction.contextualTypeArguments; return flow; @@ -494,7 +494,7 @@ export class Flow { var stack = parentFunction.breakStack; if (!stack) parentFunction.breakStack = [ id ]; else stack.push(id); - return parentFunction.breakLabel = id.toString(10); + return parentFunction.breakLabel = id.toString(); } /** Pops the most recent break label from the stack. */ @@ -504,7 +504,7 @@ export class Flow { var length = assert(stack.length); stack.pop(); if (length > 1) { - parentFunction.breakLabel = stack[length - 2].toString(10); + parentFunction.breakLabel = stack[length - 2].toString(); } else { parentFunction.breakLabel = null; parentFunction.breakStack = null; diff --git a/src/glue/js/float.d.ts b/src/glue/js/float.d.ts index dc28597e54..f40a1dd317 100644 --- a/src/glue/js/float.d.ts +++ b/src/glue/js/float.d.ts @@ -2,5 +2,5 @@ declare function f32_as_i32(value: f32): i32; declare function i32_as_f32(value: i32): f32; -declare function f64_as_i64(value: f64): I64; -declare function i64_as_f64(value: I64): f64; +declare function f64_as_i64(value: f64): i64; +declare function i64_as_f64(value: i64): f64; diff --git a/src/glue/js/i64.d.ts b/src/glue/js/i64.d.ts index 23ca983a6e..7bcc0941b2 100644 --- a/src/glue/js/i64.d.ts +++ b/src/glue/js/i64.d.ts @@ -1,44 +1,44 @@ /** @module glue/js *//***/ -declare type I64 = { __Long__: true }; // opaque - -declare const i64_zero: I64; -declare const i64_one: I64; - -declare function i64_new(lo: i32, hi?: i32): I64; -declare function i64_low(value: I64): i32; -declare function i64_high(value: I64): i32; - -declare function i64_add(left: I64, right: I64): I64; -declare function i64_sub(left: I64, right: I64): I64; -declare function i64_mul(left: I64, right: I64): I64; -declare function i64_div(left: I64, right: I64): I64; -declare function i64_div_u(left: I64, right: I64): I64; -declare function i64_rem(left: I64, right: I64): I64; -declare function i64_rem_u(left: I64, right: I64): I64; -declare function i64_and(left: I64, right: I64): I64; -declare function i64_or(left: I64, right: I64): I64; -declare function i64_xor(left: I64, right: I64): I64; -declare function i64_shl(left: I64, right: I64): I64; -declare function i64_shr(left: I64, right: I64): I64; -declare function i64_shr_u(left: I64, right: I64): I64; -declare function i64_not(value: I64): I64; - -declare function i64_eq(left: I64, right: I64): bool; -declare function i64_ne(left: I64, right: I64): bool; - -declare function i64_align(value: I64, alignment: i32): I64; - -declare function i64_is_i8(value: I64): bool; -declare function i64_is_i16(value: I64): bool; -declare function i64_is_i32(value: I64): bool; -declare function i64_is_u8(value: I64): bool; -declare function i64_is_u16(value: I64): bool; -declare function i64_is_u32(value: I64): bool; -declare function i64_is_bool(value: I64): bool; -declare function i64_is_f32(value: I64): bool; -declare function i64_is_f64(value: I64): bool; - -declare function i64_to_f32(value: I64): f64; -declare function i64_to_f64(value: I64): f64; -declare function i64_to_string(value: I64, unsigned?: bool): string; +declare type i64 = { __Long__: true }; // opaque + +declare const i64_zero: i64; +declare const i64_one: i64; + +declare function i64_new(lo: i32, hi?: i32): i64; +declare function i64_low(value: i64): i32; +declare function i64_high(value: i64): i32; + +declare function i64_add(left: i64, right: i64): i64; +declare function i64_sub(left: i64, right: i64): i64; +declare function i64_mul(left: i64, right: i64): i64; +declare function i64_div(left: i64, right: i64): i64; +declare function i64_div_u(left: i64, right: i64): i64; +declare function i64_rem(left: i64, right: i64): i64; +declare function i64_rem_u(left: i64, right: i64): i64; +declare function i64_and(left: i64, right: i64): i64; +declare function i64_or(left: i64, right: i64): i64; +declare function i64_xor(left: i64, right: i64): i64; +declare function i64_shl(left: i64, right: i64): i64; +declare function i64_shr(left: i64, right: i64): i64; +declare function i64_shr_u(left: i64, right: i64): i64; +declare function i64_not(value: i64): i64; + +declare function i64_eq(left: i64, right: i64): bool; +declare function i64_ne(left: i64, right: i64): bool; + +declare function i64_align(value: i64, alignment: i32): i64; + +declare function i64_is_i8(value: i64): bool; +declare function i64_is_i16(value: i64): bool; +declare function i64_is_i32(value: i64): bool; +declare function i64_is_u8(value: i64): bool; +declare function i64_is_u16(value: i64): bool; +declare function i64_is_u32(value: i64): bool; +declare function i64_is_bool(value: i64): bool; +declare function i64_is_f32(value: i64): bool; +declare function i64_is_f64(value: i64): bool; + +declare function i64_to_f32(value: i64): f64; +declare function i64_to_f64(value: i64): f64; +declare function i64_to_string(value: i64, unsigned?: bool): string; diff --git a/src/glue/js/i64.js b/src/glue/js/i64.js index 4338536350..d685ab75af 100644 --- a/src/glue/js/i64.js +++ b/src/glue/js/i64.js @@ -140,5 +140,5 @@ global.i64_to_f64 = function(value) { }; global.i64_to_string = function(value, unsigned) { - return (unsigned ? value.toUnsigned() : value).toString(10); + return (unsigned ? value.toUnsigned() : value).toString(); }; diff --git a/src/glue/wasm/i64.ts b/src/glue/wasm/i64.ts index 633a5f0aad..5440824e79 100644 --- a/src/glue/wasm/i64.ts +++ b/src/glue/wasm/i64.ts @@ -1,174 +1,172 @@ /** @module glue/wasm *//***/ -type I64 = i64; - @global -const i64_zero: I64 = 0; +const i64_zero: i64 = 0; @global -const i64_one: I64 = 1; +const i64_one: i64 = 1; @global -function i64_new(lo: i32, hi: i32 = 0): I64 { +function i64_new(lo: i32, hi: i32 = 0): i64 { return lo | (hi << 32); } @global -function i64_low(value: I64): i32 { +function i64_low(value: i64): i32 { return value; } @global -function i64_high(value: I64): i32 { +function i64_high(value: i64): i32 { return (value >>> 32); } @global -function i64_add(left: I64, right: I64): I64 { +function i64_add(left: i64, right: i64): i64 { return left + right; } @global -function i64_sub(left: I64, right: I64): I64 { +function i64_sub(left: i64, right: i64): i64 { return left - right; } @global -function i64_mul(left: I64, right: I64): I64 { +function i64_mul(left: i64, right: i64): i64 { return left * right; } @global -function i64_div(left: I64, right: I64): I64 { +function i64_div(left: i64, right: i64): i64 { return left / right; } @global -function i64_div_u(left: I64, right: I64): I64 { +function i64_div_u(left: i64, right: i64): i64 { return left / right; } @global -function i64_rem(left: I64, right: I64): I64 { +function i64_rem(left: i64, right: i64): i64 { return left % right; } @global -function i64_rem_u(left: I64, right: I64): I64 { +function i64_rem_u(left: i64, right: i64): i64 { return left % right; } @global -function i64_and(left: I64, right: I64): I64 { +function i64_and(left: i64, right: i64): i64 { return left & right; } @global -function i64_or(left: I64, right: I64): I64 { +function i64_or(left: i64, right: i64): i64 { return left | right; } @global -function i64_xor(left: I64, right: I64): I64 { +function i64_xor(left: i64, right: i64): i64 { return left ^ right; } @global -function i64_shl(left: I64, right: I64): I64 { +function i64_shl(left: i64, right: i64): i64 { return left << right; } @global -function i64_shr(left: I64, right: I64): I64 { +function i64_shr(left: i64, right: i64): i64 { return left >> right; } @global -function i64_shr_u(left: I64, right: I64): I64 { +function i64_shr_u(left: i64, right: i64): i64 { return left >>> right; } @global -function i64_not(value: I64): I64 { +function i64_not(value: i64): i64 { return ~value; } @global -function i64_eq(left: I64, right: I64): bool { +function i64_eq(left: i64, right: i64): bool { return left == right; } @global -function i64_ne(left: I64, right: I64): bool { +function i64_ne(left: i64, right: i64): bool { return left != right; } @global -function i64_align(value: I64, alignment: i64): I64 { +function i64_align(value: i64, alignment: i64): i64 { var mask: i64 = alignment - 1; assert(alignment && (alignment & mask) == 0); return (value + mask) & ~mask; } @global -function i64_is_i8(value: I64): bool { +function i64_is_i8(value: i64): bool { return value >= i8.MIN_VALUE && value <= i8.MAX_VALUE; } @global -function i64_is_i16(value: I64): bool { +function i64_is_i16(value: i64): bool { return value >= i16.MIN_VALUE && value <= i16.MAX_VALUE; } @global -function i64_is_i32(value: I64): bool { +function i64_is_i32(value: i64): bool { return value >= i32.MIN_VALUE && value <= i32.MAX_VALUE; } @global -function i64_is_u8(value: I64): bool { +function i64_is_u8(value: i64): bool { return value >= 0 && value <= u8.MAX_VALUE; } @global -function i64_is_u16(value: I64): bool { +function i64_is_u16(value: i64): bool { return value >= 0 && value <= u16.MAX_VALUE; } @global -function i64_is_u32(value: I64): bool { +function i64_is_u32(value: i64): bool { return value >= 0 && value <= u32.MAX_VALUE; } @global -function i64_is_bool(value: I64): bool { +function i64_is_bool(value: i64): bool { return value === 0 || value === 1; } @global -function i64_is_f32(value: I64): bool { +function i64_is_f32(value: i64): bool { return value >= f32.MIN_SAFE_INTEGER && value <= f32.MAX_SAFE_INTEGER; } @global -function i64_is_f64(value: I64): bool { +function i64_is_f64(value: i64): bool { return value >= f64.MIN_SAFE_INTEGER && value <= f64.MAX_SAFE_INTEGER; } @global -function i64_to_f32(value: I64): f32 { +function i64_to_f32(value: i64): f32 { return value; } @global -function i64_to_f64(value: I64): f64 { +function i64_to_f64(value: i64): f64 { return value; } import { CharCode } from "../../util"; @global -function i64_to_string(value: I64, unsigned: bool = false): string { +function i64_to_string(value: i64, unsigned: bool = false): string { var chars = new Array(); if (!unsigned && value < 0) { chars.push(CharCode.MINUS); diff --git a/src/index.ts b/src/index.ts index ea4fa60787..4f2ce40e18 100644 --- a/src/index.ts +++ b/src/index.ts @@ -204,20 +204,26 @@ export function buildTSD(program: Program): string { export function buildRTTI(program: Program): string { var sb = new Array(); sb.push("{\n \"names\": [\n"); - for (let cls of program.managedClasses.values()) { + // for (let cls of program.managedClasses.values()) { + for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let cls = unchecked(_values[i]); sb.push(" \""); sb.push(cls.internalName); sb.push("\",\n"); } sb.push(" ],\n \"base\": [\n"); - for (let cls of program.managedClasses.values()) { + // for (let cls of program.managedClasses.values()) { + for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let cls = unchecked(_values[i]); let base = cls.base; sb.push(" "); sb.push(base ? base.id.toString() : "0"); sb.push(",\n"); } sb.push(" ],\n \"flags\": [\n"); - for (let cls of program.managedClasses.values()) { + // for (let cls of program.managedClasses.values()) { + for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let cls = unchecked(_values[i]); sb.push(" "); sb.push(cls.rttiFlags.toString()); sb.push(",\n"); @@ -226,15 +232,11 @@ export function buildRTTI(program: Program): string { return sb.join(""); } -/** Prefix indicating a library file. */ -export { LIBRARY_PREFIX } from "./common"; - // Full API export * from "./ast"; export * from "./common"; export * from "./compiler"; export * from "./definitions"; -export * from "./diagnosticMessages.generated"; export * from "./diagnostics"; export * from "./flow"; export * from "./module"; diff --git a/src/module.ts b/src/module.ts index f55f2e71ed..ef3913885b 100644 --- a/src/module.ts +++ b/src/module.ts @@ -463,9 +463,9 @@ export enum SIMDLoadOp { export class MemorySegment { buffer: Uint8Array; - offset: I64; + offset: i64; - static create(buffer: Uint8Array, offset: I64): MemorySegment { + static create(buffer: Uint8Array, offset: i64): MemorySegment { var segment = new MemorySegment(); segment.buffer = buffer; segment.offset = offset; @@ -1440,20 +1440,17 @@ export class Module { var cStr = allocString(sourceMapUrl); var binaryPtr: usize = 0; var sourceMapPtr: usize = 0; - try { - binaryen._BinaryenModuleAllocateAndWrite(out, this.ref, cStr); - binaryPtr = binaryen.__i32_load(out); - let binaryLen = binaryen.__i32_load(out + 4); - sourceMapPtr = binaryen.__i32_load(out + 8); - let ret = new BinaryModule(); - ret.output = readBuffer(binaryPtr, binaryLen); - ret.sourceMap = readString(sourceMapPtr); - return ret; - } finally { - if (cStr) binaryen._free(cStr); - if (binaryPtr) binaryen._free(binaryPtr); - if (sourceMapPtr) binaryen._free(sourceMapPtr); - } + binaryen._BinaryenModuleAllocateAndWrite(out, this.ref, cStr); + binaryPtr = assert(binaryen.__i32_load(out)); + var binaryLen = binaryen.__i32_load(out + 4); + sourceMapPtr = binaryen.__i32_load(out + 8); // may be NULL + var ret = new BinaryModule(); + ret.output = readBuffer(binaryPtr, binaryLen); + ret.sourceMap = readString(sourceMapPtr); + binaryen._free(cStr); + binaryen._free(binaryPtr); + if (sourceMapPtr) binaryen._free(sourceMapPtr); + return ret; } toText(): string { @@ -1630,8 +1627,8 @@ export function expandType(type: NativeType): NativeType[] { var arity = binaryen._BinaryenTypeArity(type); var cArr = binaryen._malloc(arity << 2); binaryen._BinaryenTypeExpand(type, cArr); - var types = new Array(arity); - for (let i = 0; i < arity; ++i) { + var types = new Array(arity); + for (let i: u32 = 0; i < arity; ++i) { types[i] = binaryen.__i32_load(cArr + (i << 2)); } binaryen._free(cArr); diff --git a/src/program.ts b/src/program.ts index c4e6990f38..8f1731257c 100644 --- a/src/program.ts +++ b/src/program.ts @@ -37,11 +37,14 @@ import { import { Token, + Range +} from "./tokenizer"; + +import { Node, NodeKind, Source, SourceKind, - Range, DecoratorNode, DecoratorKind, TypeParameterNode, @@ -1102,7 +1105,7 @@ export class Program extends DiagnosticEmitter { } /** Registers a constant integer value within the global scope. */ - registerConstantInteger(name: string, type: Type, value: I64): void { + registerConstantInteger(name: string, type: Type, value: i64): void { assert(type.is(TypeFlags.INTEGER)); // must be an integer type var global = new Global( name, @@ -1473,7 +1476,7 @@ export class Program extends DiagnosticEmitter { } else { this.error( DiagnosticCode.Expected_0_arguments_but_got_1, - decorator.range, "1", numArgs.toString(10) + decorator.range, "1", numArgs.toString() ); } } @@ -2575,7 +2578,7 @@ export abstract class VariableLikeElement extends TypedElement { /** Constant value kind. */ constantValueKind: ConstantValueKind = ConstantValueKind.NONE; /** Constant integer value, if applicable. */ - constantIntegerValue: I64; + constantIntegerValue: i64; /** Constant float value, if applicable. */ constantFloatValue: f64; @@ -2612,7 +2615,7 @@ export abstract class VariableLikeElement extends TypedElement { } /** Applies a constant integer value to this element. */ - setConstantIntegerValue(value: I64, type: Type): void { + setConstantIntegerValue(value: i64, type: Type): void { assert(type.is(TypeFlags.INTEGER)); this.type = type; this.constantValueKind = ConstantValueKind.INTEGER; diff --git a/src/resolver.ts b/src/resolver.ts index b012e35d5e..e993117718 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -34,6 +34,10 @@ import { Flow } from "./flow"; +import { + Range +} from "./tokenizer"; + import { FunctionTypeNode, ParameterKind, @@ -43,7 +47,6 @@ import { TypeName, TypeParameterNode, Node, - Range, IdentifierExpression, CallExpression, ElementAccessExpression, @@ -436,7 +439,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() ); } return null; @@ -479,7 +482,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() ); } return null; @@ -530,7 +533,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() ); } return null; @@ -574,7 +577,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() ); } return null; @@ -662,8 +665,8 @@ export class Resolver extends DiagnosticEmitter { (typeArgumentNodes)[argumentCount - 1].range ) : assert(alternativeReportNode).range, - (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(10), - argumentCount.toString(10) + (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(), + argumentCount.toString() ); return null; } @@ -746,7 +749,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_arguments_but_got_1, - node.range, numParameters.toString(10), numArguments.toString(10) + node.range, numParameters.toString(), numArguments.toString() ); } return null; @@ -1511,7 +1514,7 @@ export class Resolver extends DiagnosticEmitter { /** Determines the final type of an integer literal given the specified contextual type. */ determineIntegerLiteralType( /** Integer literal value. */ - intValue: I64, + intValue: i64, /** Contextual type. */ ctxType: Type ): Type { diff --git a/src/tokenizer.ts b/src/tokenizer.ts index b0103af3f7..85ffc797ce 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -1272,7 +1272,7 @@ export class Tokenizer extends DiagnosticEmitter { return true; } - readInteger(): I64 { + readInteger(): i64 { var text = this.source.text; if (this.pos + 2 < this.end && text.charCodeAt(this.pos) == CharCode._0) { switch (text.charCodeAt(this.pos + 1) | 32) { @@ -1303,7 +1303,7 @@ export class Tokenizer extends DiagnosticEmitter { return this.readDecimalInteger(); } - readHexInteger(): I64 { + readHexInteger(): i64 { var text = this.source.text; var start = this.pos; var value = i64_new(0); @@ -1360,7 +1360,7 @@ export class Tokenizer extends DiagnosticEmitter { return value; } - readDecimalInteger(): I64 { + readDecimalInteger(): i64 { var text = this.source.text; var start = this.pos; var end = this.end; @@ -1405,7 +1405,7 @@ export class Tokenizer extends DiagnosticEmitter { return value; } - readOctalInteger(): I64 { + readOctalInteger(): i64 { var text = this.source.text; var start = this.pos; var value = i64_new(0); @@ -1450,7 +1450,7 @@ export class Tokenizer extends DiagnosticEmitter { return value; } - readBinaryInteger(): I64 { + readBinaryInteger(): i64 { var text = this.source.text; var start = this.pos; var value = i64_new(0); diff --git a/src/types.ts b/src/types.ts index 96ae9b9a14..ef89d9e4c3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -696,7 +696,7 @@ var cachedDefaultParameterNames: string[] | null = null; export function getDefaultParameterName(index: i32): string { if (!cachedDefaultParameterNames) cachedDefaultParameterNames = []; for (let i = cachedDefaultParameterNames.length; i <= index; ++i) { - cachedDefaultParameterNames.push("arg$" + i.toString(10)); + cachedDefaultParameterNames.push("arg$" + i.toString()); } return cachedDefaultParameterNames[index - 1]; } diff --git a/src/util/binary.ts b/src/util/binary.ts index 83e0aff0d3..887759d7fd 100644 --- a/src/util/binary.ts +++ b/src/util/binary.ts @@ -39,14 +39,14 @@ export function writeI32(value: i32, buffer: Uint8Array, offset: i32): void { } /** Reads a 64-bit integer from the specified buffer. */ -export function readI64(buffer: Uint8Array, offset: i32): I64 { +export function readI64(buffer: Uint8Array, offset: i32): i64 { var lo = readI32(buffer, offset); var hi = readI32(buffer, offset + 4); return i64_new(lo, hi); } /** Writes a 64-bit integer to the specified buffer. */ -export function writeI64(value: I64, buffer: Uint8Array, offset: i32): void { +export function writeI64(value: i64, buffer: Uint8Array, offset: i32): void { writeI32(i64_low(value), buffer, offset); writeI32(i64_high(value), buffer, offset + 4); } diff --git a/src/util/bitset.ts b/src/util/bitset.ts index 764d964d13..df36ca293f 100644 --- a/src/util/bitset.ts +++ b/src/util/bitset.ts @@ -1,7 +1,7 @@ /** @module util *//***/ /** Tests if the bit at the specified index is set within a 64-bit map. */ -export function bitsetIs(map: I64, index: i32): bool { +export function bitsetIs(map: i64, index: i32): bool { assert(index >= 0 && index < 64); return i64_ne( i64_and( @@ -16,7 +16,7 @@ export function bitsetIs(map: I64, index: i32): bool { } /** Sets or unsets the bit at the specified index within a 64-bit map and returns the new map. */ -export function bitsetSet(map: I64, index: i32, isSet: bool): I64 { +export function bitsetSet(map: i64, index: i32, isSet: bool): i64 { assert(index >= 0 && index < 64); return isSet ? i64_or( From eace4adcc8d34427563810a10bd33742554361b9 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 28 Feb 2020 20:23:28 +0100 Subject: [PATCH 07/28] refactor hell part 1, down to 696 --- package.json | 3 +- src/ast.ts | 6 +- src/builtins.ts | 4933 +++++++++++++++++++++------------------- src/compiler.ts | 2 +- src/glue/binaryen.d.ts | 14 +- src/module.ts | 8 +- src/tokenizer.ts | 162 +- 7 files changed, 2733 insertions(+), 2395 deletions(-) diff --git a/package.json b/package.json index 591c8bf439..66ce0f03d6 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,8 @@ "all": "npm run check && npm run make", "docs": "typedoc --tsconfig tsconfig-docs.json --mode modules --name \"AssemblyScript Compiler API\" --out ./docs/api --ignoreCompilerErrors --excludeNotExported --excludePrivate --excludeExternals --exclude **/std/** --includeDeclarations --readme src/README.md", "prepublishOnly": "node scripts/prepublish", - "postpublish": "node scripts/postpublish" + "postpublish": "node scripts/postpublish", + "asbuild": "node bin/asc src/glue/wasm/index.ts src/index.ts" }, "releaseFiles": [ "lib/rtrace/index.d.ts", diff --git a/src/ast.ts b/src/ast.ts index bb6ec1e716..4062e98a39 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -1452,8 +1452,10 @@ export class CallExpression extends Expression { get typeArgumentsRange(): Range { var typeArguments = this.typeArguments; var numTypeArguments: i32; - if (typeArguments && (numTypeArguments = typeArguments.length)) { - return Range.join(typeArguments[0].range, typeArguments[numTypeArguments - 1].range); + if (typeArguments) { + if (numTypeArguments = typeArguments.length) { + return Range.join(typeArguments[0].range, typeArguments[numTypeArguments - 1].range); + } } return this.expression.range; } diff --git a/src/builtins.ts b/src/builtins.ts index ab6bfb81c8..5ea62b0b44 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -10,11 +10,11 @@ } from "./compiler"; import { - DiagnosticCode + DiagnosticCode, + DiagnosticCategory } from "./diagnostics"; import { - Node, NodeKind, Expression, LiteralKind, @@ -568,2057 +568,2634 @@ export namespace BuiltinNames { export const Float64Array = "~lib/typedarray/Float64Array"; } -/** Compiles a call to a built-in function. */ -export function compileCall( - /* Compiler reference. */ - compiler: Compiler, - /** Respective function prototype. */ - prototype: FunctionPrototype, - /** Pre-resolved type arguments. */ - typeArguments: Type[] | null, - /** Operand expressions. */ - operands: Expression[], +/** Builtin compilation context. */ +class BuiltinContext { + /** Compiler reference. */ + compiler: Compiler; + /** Prototype being called. */ + prototype: FunctionPrototype; + /** Provided type arguments. */ + typeArguments: Type[] | null; + /** Provided operands. */ + operands: Expression[]; /** Contextual type. */ - contextualType: Type, + contextualType: Type; /** Respective call expression. */ - reportNode: CallExpression, - /** Indicates that contextual type is ASM type. */ - isAsm: bool = false -): ExpressionRef { + reportNode: CallExpression; + /** Whether originating from inline assembly. */ + isAsm: bool; +} + +/** Registered builtins. */ +export const builtins = new Map ExpressionRef>(); + +// === Static type evaluation ================================================================= + +// isInteger() / isInteger(value: T) -> bool +function builtin_isInteger(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) + ? module.i32(1) + : module.i32(0); +} +builtins.set(BuiltinNames.isInteger, builtin_isInteger); - switch (prototype.internalName) { +// isFloat() / isFloat(value: T) -> bool +function builtin_isFloat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return type.is(TypeFlags.FLOAT) + ? module.i32(1) + : module.i32(0); +} +builtins.set(BuiltinNames.isFloat, builtin_isFloat); - // === Static type evaluation ================================================================= +// isBoolean() / isBoolean(value: T) -> bool +function builtin_isBoolean(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return type == Type.bool + ? module.i32(1) + : module.i32(0); +} +builtins.set(BuiltinNames.isBoolean, builtin_isBoolean); - case BuiltinNames.isInteger: { // isInteger() / isInteger(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) - ? module.i32(1) - : module.i32(0); - } - case BuiltinNames.isFloat: { // isFloat() / isFloat(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.FLOAT) - ? module.i32(1) - : module.i32(0); - } - case BuiltinNames.isBoolean: { // isBoolean() / isBoolean(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type == Type.bool - ? module.i32(1) - : module.i32(0); - } - case BuiltinNames.isSigned: { // isSigned() / isSigned(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.SIGNED) - ? module.i32(1) - : module.i32(0); +// isSigned() / isSigned(value: T) -> bool +function builtin_isSigned(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return type.is(TypeFlags.SIGNED) + ? module.i32(1) + : module.i32(0); +} +builtins.set(BuiltinNames.isSigned, builtin_isSigned); + +// isReference() / isReference(value: T) -> bool +function builtin_isReference(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return type.is(TypeFlags.REFERENCE) + ? module.i32(1) + : module.i32(0); +} +builtins.set(BuiltinNames.isReference, builtin_isReference); + +// isString() / isString(value: T) -> bool +function builtin_isString(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let stringInstance = compiler.program.stringInstance; + if (stringInstance && classReference.isAssignableTo(stringInstance)) return module.i32(1); } - case BuiltinNames.isReference: { // isReference() / isReference(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.REFERENCE) - ? module.i32(1) - : module.i32(0); + } + return module.i32(0); +} +builtins.set(BuiltinNames.isString, builtin_isString); + +// isArray() / isArray(value: T) -> bool +function builtin_isArray(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + return module.i32(classReference.prototype.extends(compiler.program.arrayPrototype) ? 1 : 0); } - case BuiltinNames.isString: { // isString() / isString(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let classReference = type.classReference; - if (classReference) { - let stringInstance = compiler.program.stringInstance; - if (stringInstance && classReference.isAssignableTo(stringInstance)) return module.i32(1); - } - } - return module.i32(0); + } + return module.i32(0); +} +builtins.set(BuiltinNames.isArray, builtin_isArray); + +// isArrayLike() / isArrayLike(value: T) -> bool +function builtin_isArrayLike(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + return module.i32(classReference.isArrayLike ? 1 : 0); } - case BuiltinNames.isArray: { // isArray() / isArray(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let classReference = type.classReference; - if (classReference) { - return module.i32(classReference.prototype.extends(compiler.program.arrayPrototype) ? 1 : 0); - } + } + return module.i32(0); +} +builtins.set(BuiltinNames.isArrayLike, builtin_isArrayLike); + +// isFunction / isFunction(value: T) -> bool +function builtin_isFunction(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.signatureReference ? 1 : 0); +} +builtins.set(BuiltinNames.isFunction, builtin_isFunction); + +// isNullable / isNullable(value: T) -> bool +function builtin_isNullable(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.is(TypeFlags.NULLABLE) ? 1 : 0); +} +builtins.set(BuiltinNames.isNullable, builtin_isNullable); + +// isDefined(expression) -> bool +function builtin_isDefined(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.bool; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var element = compiler.resolver.lookupExpression( + ctx.operands[0], + compiler.currentFlow, + Type.auto, + ReportMode.SWALLOW + ); + return module.i32(element ? 1 : 0); +} +builtins.set(BuiltinNames.isDefined, builtin_isDefined); + +// isConstant(expression) -> bool +function builtin_isConstant(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.bool; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var expr = compiler.compileExpression(ctx.operands[0], Type.auto); + compiler.currentType = Type.bool; + return module.i32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0); +} +builtins.set(BuiltinNames.isConstant, builtin_isConstant); + +// isManaged() -> bool +function builtin_isManaged(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.isManaged ? 1 : 0); +} +builtins.set(BuiltinNames.isManaged, builtin_isManaged); + +// isVoid() -> bool +function builtin_isVoid(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.kind == TypeKind.VOID ? 1 : 0); +} +builtins.set(BuiltinNames.isVoid, builtin_isVoid); + +// lengthof() -> i32 +function builtin_lengthof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.i32; + if (!type) return module.unreachable(); + var signatureReference = type.signatureReference; + if (!signatureReference) { + compiler.error( + DiagnosticCode.Type_0_has_no_call_signatures, + ctx.reportNode.range, type.toString() + ); + return module.unreachable(); + } + return module.i32(signatureReference.parameterTypes.length); +} +builtins.set(BuiltinNames.lengthof, builtin_lengthof); + +// sizeof() -> usize* +function builtin_sizeof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = compiler.options.usizeType; + if ( + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + var type = ctx.typeArguments![0]; + var byteSize = type.byteSize; + if (!byteSize) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "sizeof", type.toString() + ); + return module.unreachable(); + } + return contextualUsize(compiler, i64_new(byteSize), ctx.contextualType); +} +builtins.set(BuiltinNames.sizeof, builtin_sizeof); + +// alignof() -> usize* +function builtin_alignof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = compiler.options.usizeType; + if ( + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + var type = ctx.typeArguments![0]; + var byteSize = type.byteSize; + if (!isPowerOf2(byteSize)) { // implies == 0 + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "alignof", type.toString() + ); + return module.unreachable(); + } + return contextualUsize(compiler, i64_new(ctz(byteSize)), ctx.contextualType); +} +builtins.set(BuiltinNames.alignof, builtin_alignof); + +// offsetof(fieldName?: string) -> usize* +function builtin_offsetof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = compiler.options.usizeType; + if ( + checkTypeRequired(ctx) | + checkArgsOptional(ctx, 0, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var contextualType = ctx.contextualType; + var type = ctx.typeArguments![0]; + var classType = type.classReference; + if (!(type.is(TypeFlags.REFERENCE) && classType !== null)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "offsetof", type.toString() + ); + if (compiler.options.isWasm64) { + if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { + compiler.currentType = Type.u32; } - return module.i32(0); - } - case BuiltinNames.isArrayLike: { // isArrayLike() / isArrayLike(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let classReference = type.classReference; - if (classReference) { - return module.i32(classReference.isArrayLike ? 1 : 0); - } + } else { + if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { + compiler.currentType = Type.u64; } - return module.i32(0); - } - case BuiltinNames.isFunction: { // isFunction / isFunction(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.signatureReference ? 1 : 0); } - case BuiltinNames.isNullable: { // isNullable / isNullable(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.is(TypeFlags.NULLABLE) ? 1 : 0); + return module.unreachable(); + } + var offset: i32; + if (operands.length) { + if ( + operands[0].kind != NodeKind.LITERAL || + (operands[0]).literalKind != LiteralKind.STRING + ) { + compiler.error( + DiagnosticCode.String_literal_expected, + operands[0].range + ); + return module.unreachable(); } - case BuiltinNames.isDefined: { // isDefined(expression) -> bool - compiler.currentType = Type.bool; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let element = compiler.resolver.lookupExpression( - operands[0], - compiler.currentFlow, - Type.auto, - ReportMode.SWALLOW + let fieldName = (operands[0]).value; + let field = classType.members ? classType.members.get(fieldName) : null; + if (!(field && field.kind == ElementKind.FIELD)) { + compiler.error( + DiagnosticCode.Type_0_has_no_property_1, + operands[0].range, classType.internalName, fieldName ); - return module.i32(element ? 1 : 0); + return module.unreachable(); } - case BuiltinNames.isConstant: { // isConstant(expression) -> bool - compiler.currentType = Type.bool; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let expr = compiler.compileExpression(operands[0], Type.auto); - compiler.currentType = Type.bool; - return module.i32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0); + offset = (field).memoryOffset; + } else { + offset = classType.nextMemoryOffset; + } + return contextualUsize(compiler, i64_new(offset), contextualType); +} +builtins.set(BuiltinNames.offsetof, builtin_offsetof); + +// nameof -> string +function builtin_nameof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var resultType = evaluateConstantType(ctx); + if (!resultType) { + compiler.currentType = compiler.program.stringInstance.type; + return module.unreachable(); + } + var value: string; + if (resultType.is(TypeFlags.REFERENCE)) { + let classReference = resultType.classReference; + if (classReference) { + value = classReference.name; + } else { + let signatureReference = resultType.signatureReference; + if (signatureReference) { + value = "Function"; + } else { + value = "Anyref"; + } } - case BuiltinNames.isManaged: { // isManaged() -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.isManaged ? 1 : 0); + } else { + switch (resultType.kind) { + case TypeKind.BOOL: { value = "bool"; break; } + case TypeKind.I8: { value = "i8"; break; } + case TypeKind.U8: { value = "u8"; break; } + case TypeKind.I16: { value = "i16"; break; } + case TypeKind.U16: { value = "u16"; break; } + case TypeKind.I32: { value = "i32"; break; } + case TypeKind.U32: { value = "u32"; break; } + case TypeKind.F32: { value = "f32"; break; } + case TypeKind.I64: { value = "i64"; break; } + case TypeKind.U64: { value = "u64"; break; } + case TypeKind.F64: { value = "f64"; break; } + case TypeKind.ISIZE: { value = "isize"; break; } + case TypeKind.USIZE: { value = "usize"; break; } + case TypeKind.V128: { value = "v128"; break; } + case TypeKind.ANYREF: { value = "anyref"; break; } + default: assert(false); + case TypeKind.VOID: { value = "void"; break; } } - case BuiltinNames.isVoid: { // isVoid() -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.kind == TypeKind.VOID ? 1 : 0); + } + return compiler.ensureStaticString(value); +} +builtins.set(BuiltinNames.nameof, builtin_nameof); + +// idof -> u32 +function builtin_idof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.u32; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let signatureReference = type.signatureReference; + if (signatureReference) { + return module.i32(signatureReference.id); + } + let classReference = type.classReference; + if (classReference !== null && !classReference.hasDecorator(DecoratorFlags.UNMANAGED)) { + return module.i32(classReference.id); } - case BuiltinNames.lengthof: { // lengthof() -> i32 - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.i32; - if (!type) return module.unreachable(); - let signatureReference = type.signatureReference; - if (!signatureReference) { - compiler.error( - DiagnosticCode.Type_0_has_no_call_signatures, - reportNode.range, type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "idof", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.idof, builtin_idof); + +// === Math =================================================================================== + +// clz(value: T) -> T +function builtin_clz(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(ctx.operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(ctx.operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.BOOL: // not wrapped + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.ClzI32, arg0); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.ClzI64 + : UnaryOp.ClzI32, + arg0 ); - return module.unreachable(); } - return module.i32(signatureReference.parameterTypes.length); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.ClzI64, arg0); } - case BuiltinNames.sizeof: { // sizeof() -> usize* - compiler.currentType = compiler.options.usizeType; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let byteSize = type.byteSize; - if (!byteSize) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "sizeof", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "clz", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.clz, builtin_clz); + +// ctz(value: T) -> T +function builtin_ctz(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.BOOL: // not wrapped + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.CtzI32, arg0); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.CtzI64 + : UnaryOp.CtzI32, + arg0 ); - return module.unreachable(); } - return contextualUsize(compiler, i64_new(byteSize), contextualType); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.CtzI64, arg0); } - case BuiltinNames.alignof: { // alignof() -> usize* - compiler.currentType = compiler.options.usizeType; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let byteSize = type.byteSize; - if (!isPowerOf2(byteSize)) { // implies == 0 - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "alignof", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "ctz", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.ctz, builtin_ctz); + +// popcnt(value: T) -> T +function builtin_popcnt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (compiler.currentType.kind) { + case TypeKind.BOOL: // not wrapped + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.PopcntI32, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.PopcntI64, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.PopcntI64 + : UnaryOp.PopcntI32, + arg0 ); - return module.unreachable(); } - return contextualUsize(compiler, i64_new(ctz(byteSize)), contextualType); } - case BuiltinNames.offsetof: { // offsetof(fieldName?: string) -> usize* - compiler.currentType = compiler.options.usizeType; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 0, 1, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let classType = type.classReference; - if (!(type.is(TypeFlags.REFERENCE) && classType !== null)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "offsetof", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "popcnt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.popcnt, builtin_popcnt); + +// rotl(value: T, shift: T) -> T +function builtin_rotl(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.RotlI32, arg0, arg1), + type ); - if (compiler.options.isWasm64) { - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - } - } else { - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - } - } - return module.unreachable(); } - let offset: i32; - if (operands.length) { - if ( - operands[0].kind != NodeKind.LITERAL || - (operands[0]).literalKind != LiteralKind.STRING - ) { - compiler.error( - DiagnosticCode.String_literal_expected, - operands[0].range - ); - return module.unreachable(); - } - let fieldName = (operands[0]).value; - let field = classType.members ? classType.members.get(fieldName) : null; - if (!(field && field.kind == ElementKind.FIELD)) { - compiler.error( - DiagnosticCode.Type_0_has_no_property_1, - operands[0].range, classType.internalName, fieldName - ); - return module.unreachable(); - } - offset = (field).memoryOffset; - } else { - offset = classType.nextMemoryOffset; + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.RotlI32, arg0, arg1); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.RotlI64 + : BinaryOp.RotlI32, + arg0, arg1 + ); } - return contextualUsize(compiler, i64_new(offset), contextualType); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.RotlI64, arg0, arg1); } - case BuiltinNames.nameof: { - let resultType = evaluateConstantType(compiler, typeArguments, operands, reportNode); - if (!resultType) { - compiler.currentType = compiler.program.stringInstance.type; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "rotl", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.rotl, builtin_rotl); + +// rotr(value: T, shift: T) -> T +function builtin_rotr(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.RotrI32, arg0, arg1), + type + ); } - let value: string; - if (resultType.is(TypeFlags.REFERENCE)) { - let classReference = resultType.classReference; - if (classReference) { - value = classReference.name; - } else { - let signatureReference = resultType.signatureReference; - if (signatureReference) { - value = "Function"; - } else { - value = "Anyref"; - } - } - } else { - switch (resultType.kind) { - case TypeKind.BOOL: { value = "bool"; break; } - case TypeKind.I8: { value = "i8"; break; } - case TypeKind.U8: { value = "u8"; break; } - case TypeKind.I16: { value = "i16"; break; } - case TypeKind.U16: { value = "u16"; break; } - case TypeKind.I32: { value = "i32"; break; } - case TypeKind.U32: { value = "u32"; break; } - case TypeKind.F32: { value = "f32"; break; } - case TypeKind.I64: { value = "i64"; break; } - case TypeKind.U64: { value = "u64"; break; } - case TypeKind.F64: { value = "f64"; break; } - case TypeKind.ISIZE: { value = "isize"; break; } - case TypeKind.USIZE: { value = "usize"; break; } - case TypeKind.V128: { value = "v128"; break; } - case TypeKind.ANYREF: { value = "anyref"; break; } - default: assert(false); - case TypeKind.VOID: { value = "void"; break; } - } + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.RotrI32, arg0, arg1); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.RotrI64 + : BinaryOp.RotrI32, + arg0, arg1 + ); } - return compiler.ensureStaticString(value); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.RotrI64, arg0, arg1); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "rotr", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.rotr, builtin_rotr); - // === Math =================================================================================== +// abs(value: T) -> T +function builtin_abs(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: { + let flow = compiler.currentFlow; - case BuiltinNames.clz: { // clz(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.BOOL: // not wrapped - case TypeKind.I8: - case TypeKind.U8: - case TypeKind.I16: - case TypeKind.U16: - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.ClzI32, arg0); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.ClzI64 - : UnaryOp.ClzI32, - arg0 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.ClzI64, arg0); - } + // possibly overflows, e.g. abs(-128) == 128 + let temp1 = flow.getTempLocal(Type.i32); + let temp2 = flow.getTempLocal(Type.i32); + // (x + (x >> 31)) ^ (x >> 31) + let ret = module.binary(BinaryOp.XorI32, + module.binary(BinaryOp.AddI32, + module.local_tee( + temp2.index, + module.binary(BinaryOp.ShrI32, + module.local_tee(temp1.index, arg0), + module.i32(31) + ) + ), + module.local_get(temp1.index, NativeType.I32) + ), + module.local_get(temp2.index, NativeType.I32) + ); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "clz", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.ctz: { // ctz(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.BOOL: // not wrapped - case TypeKind.I8: - case TypeKind.U8: - case TypeKind.I16: - case TypeKind.U16: - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.CtzI32, arg0); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.CtzI64 - : UnaryOp.CtzI32, - arg0 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.CtzI64, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "ctz", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.popcnt: { // popcnt(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (compiler.currentType.kind) { - case TypeKind.BOOL: // not wrapped - case TypeKind.I8: - case TypeKind.U8: - case TypeKind.I16: - case TypeKind.U16: - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.PopcntI32, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.PopcntI64, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.PopcntI64 - : UnaryOp.PopcntI32, - arg0 - ); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "popcnt", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.rotl: { // rotl(value: T, shift: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.BOOL: { - return compiler.ensureSmallIntegerWrap( - module.binary(BinaryOp.RotlI32, arg0, arg1), - type - ); - } - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.RotlI32, arg0, arg1); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.RotlI64 - : BinaryOp.RotlI32, - arg0, arg1 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.RotlI64, arg0, arg1); - } + case TypeKind.ISIZE: { + let options = compiler.options; + let flow = compiler.currentFlow; + let isWasm64 = options.isWasm64; + + let temp1 = flow.getTempLocal(options.usizeType); + let temp2 = flow.getTempLocal(options.usizeType); + let ret = module.binary(isWasm64 ? BinaryOp.XorI64 : BinaryOp.XorI32, + module.binary(isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32, + module.local_tee( + temp2.index, + module.binary(isWasm64 ? BinaryOp.ShrI64 : BinaryOp.ShrI32, + module.local_tee(temp1.index, arg0), + isWasm64 ? module.i64(63) : module.i32(31) + ) + ), + module.local_get(temp1.index, options.nativeSizeType) + ), + module.local_get(temp2.index, options.nativeSizeType) + ); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "rotl", type.toString() - ); - return module.unreachable(); + case TypeKind.I64: { + let flow = compiler.currentFlow; + + let temp1 = flow.getTempLocal(Type.i64); + let temp2 = flow.getTempLocal(Type.i64); + // (x + (x >> 63)) ^ (x >> 63) + let ret = module.binary(BinaryOp.XorI64, + module.binary(BinaryOp.AddI64, + module.local_tee( + temp2.index, + module.binary(BinaryOp.ShrI64, + module.local_tee(temp1.index, arg0), + module.i64(63) + ) + ), + module.local_get(temp1.index, NativeType.I64) + ), + module.local_get(temp2.index, NativeType.I64) + ); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; + } + case TypeKind.USIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.BOOL: return arg0; + case TypeKind.F32: return module.unary(UnaryOp.AbsF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.AbsF64, arg0); } - case BuiltinNames.rotr: { // rotr(value: T, shift: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.BOOL: { - return compiler.ensureSmallIntegerWrap( - module.binary(BinaryOp.RotrI32, arg0, arg1), - type - ); - } - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.RotrI32, arg0, arg1); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.RotrI64 - : BinaryOp.RotrI32, - arg0, arg1 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.RotrI64, arg0, arg1); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "abs", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.abs, builtin_abs); + +// max(left: T, right: T) -> T +function builtin_max(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1: ExpressionRef; + if (!typeArguments && isNumericLiteral(left)) { // prefer right type + arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "rotr", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.abs: { // abs(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: { - let flow = compiler.currentFlow; - - // possibly overflows, e.g. abs(-128) == 128 - let temp1 = flow.getTempLocal(Type.i32); - let temp2 = flow.getTempLocal(Type.i32); - // (x + (x >> 31)) ^ (x >> 31) - let ret = module.binary(BinaryOp.XorI32, - module.binary(BinaryOp.AddI32, - module.local_tee( - temp2.index, - module.binary(BinaryOp.ShrI32, - module.local_tee(temp1.index, arg0), - module.i32(31) - ) - ), - module.local_get(temp1.index, NativeType.I32) - ), - module.local_get(temp2.index, NativeType.I32) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - case TypeKind.ISIZE: { - let options = compiler.options; - let flow = compiler.currentFlow; - let isWasm64 = options.isWasm64; - - let temp1 = flow.getTempLocal(options.usizeType); - let temp2 = flow.getTempLocal(options.usizeType); - let ret = module.binary(isWasm64 ? BinaryOp.XorI64 : BinaryOp.XorI32, - module.binary(isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32, - module.local_tee( - temp2.index, - module.binary(isWasm64 ? BinaryOp.ShrI64 : BinaryOp.ShrI32, - module.local_tee(temp1.index, arg0), - isWasm64 ? module.i64(63) : module.i32(31) - ) - ), - module.local_get(temp1.index, options.nativeSizeType) - ), - module.local_get(temp2.index, options.nativeSizeType) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - case TypeKind.I64: { - let flow = compiler.currentFlow; - - let temp1 = flow.getTempLocal(Type.i64); - let temp2 = flow.getTempLocal(Type.i64); - // (x + (x >> 63)) ^ (x >> 63) - let ret = module.binary(BinaryOp.XorI64, - module.binary(BinaryOp.AddI64, - module.local_tee( - temp2.index, - module.binary(BinaryOp.ShrI64, - module.local_tee(temp1.index, arg0), - module.i64(63) - ) - ), - module.local_get(temp1.index, NativeType.I64) - ), - module.local_get(temp2.index, NativeType.I64) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - case TypeKind.USIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.BOOL: return arg0; - case TypeKind.F32: return module.unary(UnaryOp.AbsF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.AbsF64, arg0); - } + } else { + arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: { op = BinaryOp.GtI32; break; } + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: { op = BinaryOp.GtU32; break; } + case TypeKind.I64: { op = BinaryOp.GtI64; break; } + case TypeKind.U64: { op = BinaryOp.GtU64; break; } + case TypeKind.ISIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.GtI64 + : BinaryOp.GtI32; + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "abs", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.max: { // max(left: T, right: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let left = operands[0]; - let arg0 = typeArguments - ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1: ExpressionRef; - if (!typeArguments && isNumericLiteral(left)) { // prefer right type - arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); - if (compiler.currentType != type) { - arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - } else { - arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - let op: BinaryOp = -1; - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: { op = BinaryOp.GtI32; break; } - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: { op = BinaryOp.GtU32; break; } - case TypeKind.I64: { op = BinaryOp.GtI64; break; } - case TypeKind.U64: { op = BinaryOp.GtU64; break; } - case TypeKind.ISIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.GtI64 - : BinaryOp.GtI32; - break; - } - case TypeKind.USIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.GtU64 - : BinaryOp.GtU32; - break; - } - case TypeKind.F32: return module.binary(BinaryOp.MaxF32, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MaxF64, arg0, arg1); - } - if (op != -1) { - let flow = compiler.currentFlow; - let nativeType = type.toNativeType(); - let temp1 = flow.getTempLocal(type); - flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); - let temp2 = flow.getTempLocal(type); - flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); - let ret = module.select( - module.local_tee(temp1.index, arg0), - module.local_tee(temp2.index, arg1), - module.binary(op, - module.local_get(temp1.index, nativeType), - module.local_get(temp2.index, nativeType) - ) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.GtU64 + : BinaryOp.GtU32; + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "max", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.MaxF32, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MaxF64, arg0, arg1); } - case BuiltinNames.min: { // min(left: T, right: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let left = operands[0]; - let arg0 = typeArguments - ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1: ExpressionRef; - if (!typeArguments && isNumericLiteral(left)) { // prefer right type - arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); - if (compiler.currentType != type) { - arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - } else { - arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - let op: BinaryOp = -1; - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: { op = BinaryOp.LtI32; break; } - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: { op = BinaryOp.LtU32; break; } - case TypeKind.I64: { op = BinaryOp.LtI64; break; } - case TypeKind.U64: { op = BinaryOp.LtU64; break; } - case TypeKind.ISIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.LtI64 - : BinaryOp.LtI32; - break; - } - case TypeKind.USIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.LtU64 - : BinaryOp.LtU32; - break; - } - case TypeKind.F32: return module.binary(BinaryOp.MinF32, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MinF64, arg0, arg1); - } - if (op != -1) { - let flow = compiler.currentFlow; - let nativeType = type.toNativeType(); - let temp1 = flow.getTempLocal(type); - flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); - let temp2 = flow.getTempLocal(type); - flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); - let ret = module.select( - module.local_tee(temp1.index, arg0), - module.local_tee(temp2.index, arg1), - module.binary(op, - module.local_get(temp1.index, nativeType), - module.local_get(temp2.index, nativeType) - ) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "min", type.toString() + if (op != -1) { + let flow = compiler.currentFlow; + let nativeType = type.toNativeType(); + let temp1 = flow.getTempLocal(type); + flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); + let temp2 = flow.getTempLocal(type); + flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); + let ret = module.select( + module.local_tee(temp1.index, arg0), + module.local_tee(temp2.index, arg1), + module.binary(op, + module.local_get(temp1.index, nativeType), + module.local_get(temp2.index, nativeType) + ) ); - return module.unreachable(); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - case BuiltinNames.ceil: { // ceil(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; // considered rounded - case TypeKind.F32: return module.unary(UnaryOp.CeilF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.CeilF64, arg0); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "max", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.max, builtin_max); + +// min(left: T, right: T) -> T +function builtin_min(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1: ExpressionRef; + if (!typeArguments && isNumericLiteral(left)) { // prefer right type + arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "ceil", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.floor: { // floor(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; // considered rounded - case TypeKind.F32: return module.unary(UnaryOp.FloorF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.FloorF64, arg0); - } + } else { + arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: { op = BinaryOp.LtI32; break; } + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: { op = BinaryOp.LtU32; break; } + case TypeKind.I64: { op = BinaryOp.LtI64; break; } + case TypeKind.U64: { op = BinaryOp.LtU64; break; } + case TypeKind.ISIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.LtI64 + : BinaryOp.LtI32; + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "floor", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.copysign: { // copysign(left: T, right: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - switch (type.kind) { - // TODO: does an integer version make sense? - case TypeKind.F32: return module.binary(BinaryOp.CopysignF32, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.CopysignF64, arg0, arg1); - } + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.LtU64 + : BinaryOp.LtU32; + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "copysign", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.MinF32, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MinF64, arg0, arg1); } - case BuiltinNames.nearest: { // nearest(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; - case TypeKind.F32: return module.unary(UnaryOp.NearestF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.NearestF64, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "nearest", type.toString() + if (op != -1) { + let flow = compiler.currentFlow; + let nativeType = type.toNativeType(); + let temp1 = flow.getTempLocal(type); + flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); + let temp2 = flow.getTempLocal(type); + flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); + let ret = module.select( + module.local_tee(temp1.index, arg0), + module.local_tee(temp2.index, arg1), + module.binary(op, + module.local_get(temp1.index, nativeType), + module.local_get(temp2.index, nativeType) + ) ); - return module.unreachable(); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - case BuiltinNames.reinterpret: { // reinterpret(value: *) -> T - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I32: - case TypeKind.U32: { - let arg0 = compiler.compileExpression(operands[0], Type.f32, Constraints.CONV_IMPLICIT); - compiler.currentType = type; - return module.unary(UnaryOp.ReinterpretF32, arg0); - } - case TypeKind.I64: - case TypeKind.U64: { - let arg0 = compiler.compileExpression(operands[0], Type.f64, Constraints.CONV_IMPLICIT); - compiler.currentType = type; - return module.unary(UnaryOp.ReinterpretF64, arg0); - } - case TypeKind.ISIZE: - case TypeKind.USIZE: { - let arg0 = compiler.compileExpression(operands[0], - compiler.options.isWasm64 - ? Type.f64 - : Type.f32, - Constraints.CONV_IMPLICIT - ); - compiler.currentType = type; - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.ReinterpretF64 - : UnaryOp.ReinterpretF32, - arg0 - ); - } - case TypeKind.F32: { - let arg0 = compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.f32; - return module.unary(UnaryOp.ReinterpretI32, arg0); - } - case TypeKind.F64: { - let arg0 = compiler.compileExpression(operands[0], Type.i64, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.f64; - return module.unary(UnaryOp.ReinterpretI64, arg0); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "reinterpret", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "min", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.min, builtin_min); + +// ceil(value: T) -> T +function builtin_ceil(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; // considered rounded + case TypeKind.F32: return module.unary(UnaryOp.CeilF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.CeilF64, arg0); } - case BuiltinNames.sqrt: { // sqrt(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - // TODO: integer versions (that return f64 or convert)? - case TypeKind.F32: return module.unary(UnaryOp.SqrtF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SqrtF64, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "sqrt", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "ceil", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.ceil, builtin_ceil); + +// floor(value: T) -> T +function builtin_floor(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; // considered rounded + case TypeKind.F32: return module.unary(UnaryOp.FloorF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.FloorF64, arg0); } - case BuiltinNames.trunc: { // trunc(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; // considered truncated - case TypeKind.F32: return module.unary(UnaryOp.TruncF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.TruncF64, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "trunc", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "floor", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.floor, builtin_floor); + +// copysign(left: T, right: T) -> T +function builtin_copysign(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + switch (type.kind) { + // TODO: does an integer version make sense? + case TypeKind.F32: return module.binary(BinaryOp.CopysignF32, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.CopysignF64, arg0, arg1); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "copysign", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.copysign, builtin_copysign); - // === Memory access ========================================================================== +// nearest(value: T) -> T +function builtin_nearest(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; + case TypeKind.F32: return module.unary(UnaryOp.NearestF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.NearestF64, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "nearest", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.nearest, builtin_nearest); - case BuiltinNames.load: { // load(offset: usize, immOffset?: usize, immAlign?: usize) -> T* - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let outType = ( - contextualType != Type.auto && - type.is(TypeFlags.INTEGER) && - contextualType.is(TypeFlags.INTEGER) && - contextualType.size > type.size - ) ? contextualType : type; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let numOperands = operands.length; - let immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = outType; - return module.unreachable(); - } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (numOperands == 3) { - immAlign = evaluateImmediateOffset(operands[2], compiler); - if (immAlign < 0) { - compiler.currentType = outType; - return module.unreachable(); - } - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[2].range, "Alignment", "0", naturalAlign.toString() - ); - compiler.currentType = outType; - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[2].range, "Alignment" - ); - compiler.currentType = outType; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; +// reinterpret(value: *) -> T +function builtin_reinterpret(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var type = typeArguments![0]; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I32: + case TypeKind.U32: { + let arg0 = compiler.compileExpression(operands[0], Type.f32, Constraints.CONV_IMPLICIT); + compiler.currentType = type; + return module.unary(UnaryOp.ReinterpretF32, arg0); } - compiler.currentType = outType; - return module.load( - type.byteSize, - type.is(TypeFlags.SIGNED | TypeFlags.INTEGER), - arg0, - outType.toNativeType(), - immOffset, - immAlign - ); - } - case BuiltinNames.store: { // store(offset: usize, value: T*, offset?: usize, align?: usize) -> void - compiler.currentType = Type.void; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 2, 4, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = isAsm - ? compiler.compileExpression(operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT - ); - let inType = compiler.currentType; - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] + case TypeKind.I64: + case TypeKind.U64: { + let arg0 = compiler.compileExpression(operands[0], Type.f64, Constraints.CONV_IMPLICIT); + compiler.currentType = type; + return module.unary(UnaryOp.ReinterpretF64, arg0); + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + let arg0 = compiler.compileExpression(operands[0], + compiler.options.isWasm64 + ? Type.f64 + : Type.f32, + Constraints.CONV_IMPLICIT + ); + compiler.currentType = type; + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.ReinterpretF64 + : UnaryOp.ReinterpretF32, + arg0 ); - inType = type; } - let immOffset = operands.length >= 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.void; - return module.unreachable(); + case TypeKind.F32: { + let arg0 = compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.f32; + return module.unary(UnaryOp.ReinterpretI32, arg0); } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (operands.length == 4) { - immAlign = evaluateImmediateOffset(operands[3], compiler); - if (immAlign < 0) { - compiler.currentType = Type.void; - return module.unreachable(); - } - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[3].range, "Alignment", "0", naturalAlign.toString() - ); - compiler.currentType = Type.void; - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[3].range, "Alignment" - ); - compiler.currentType = Type.void; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; + case TypeKind.F64: { + let arg0 = compiler.compileExpression(operands[0], Type.i64, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.f64; + return module.unary(UnaryOp.ReinterpretI64, arg0); } - compiler.currentType = Type.void; - return module.store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset, immAlign); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "reinterpret", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.reinterpret, builtin_reinterpret); - // === Atomics ================================================================================ +// sqrt(value: T) -> T +function builtin_sqrt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + // TODO: integer versions (that return f64 or convert)? + case TypeKind.F32: return module.unary(UnaryOp.SqrtF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.SqrtF64, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "sqrt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.sqrt, builtin_sqrt); - case BuiltinNames.atomic_load: { // load(offset: usize, immOffset?: usize) -> T* - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 2, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let outType = ( - type.is(TypeFlags.INTEGER) && - contextualType.is(TypeFlags.INTEGER) && - contextualType.size > type.size - ) ? contextualType : type; - if (!type.is(TypeFlags.INTEGER)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.load", type.toString() - ); - compiler.currentType = outType; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let immOffset = operands.length == 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = outType; - return module.unreachable(); - } - compiler.currentType = outType; - return module.atomic_load( - type.byteSize, - arg0, - outType.toNativeType(), - immOffset - ); +// trunc(value: T) -> T +function builtin_trunc(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; // considered truncated + case TypeKind.F32: return module.unary(UnaryOp.TruncF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.TruncF64, arg0); } - case BuiltinNames.atomic_store: { // store(offset: usize, value: T*, immOffset?: usize) -> void - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 2, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.INTEGER)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.store", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "trunc", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.trunc, builtin_trunc); + +// isNaN(value: T) -> bool +function builtin_isNaN(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto); + var type = compiler.currentType; + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + // never NaN + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: { + return hasSideEffects(arg0) + ? module.block(null, [ + module.drop(arg0), + module.i32(0) + ], NativeType.I32) + : module.i32(0); + } + // (t = arg0) != t + case TypeKind.F32: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.NeF32, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F32) + ); + } + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f32); + let ret = module.binary(BinaryOp.NeF32, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F32) ); - compiler.currentType = Type.void; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = isAsm - ? compiler.compileExpression( - operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F64: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.NeF64, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F64) ); - let inType = compiler.currentType; - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] + } + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f64); + let ret = module.binary(BinaryOp.NeF64, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F64) ); - inType = type; - } - let immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.void; - return module.unreachable(); + flow.freeTempLocal(temp); + return ret; } - compiler.currentType = Type.void; - return module.atomic_store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset); } - case BuiltinNames.atomic_add: // any_atomic_binary(ptr, value: T, immOffset?: usize) -> T - case BuiltinNames.atomic_sub: - case BuiltinNames.atomic_and: - case BuiltinNames.atomic_or: - case BuiltinNames.atomic_xor: - case BuiltinNames.atomic_xchg: { - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 2, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.INTEGER) || type.size < 8) { - let opName: string; - switch (prototype.internalName) { - default: assert(false); - case BuiltinNames.atomic_add: { opName = "atomic.add"; break; } - case BuiltinNames.atomic_sub: { opName = "atomic.sub"; break; } - case BuiltinNames.atomic_and: { opName = "atomic.and"; break; } - case BuiltinNames.atomic_or: { opName = "atomic.or"; break; } - case BuiltinNames.atomic_xor: { opName = "atomic.xor"; break; } - case BuiltinNames.atomic_xchg: { opName = "atomic.xchg"; break; } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "isNaN", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.isNaN, builtin_isNaN); + +// isFinite(value: T) -> bool +function builtin_isFinite(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto); + var type = compiler.currentType; + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + // always finite + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: { + return hasSideEffects(arg0) + ? module.block(null, [ + module.drop(arg0), + module.i32(1) + ], NativeType.I32) + : module.i32(1); + } + // (t = arg0) - t == 0 + case TypeKind.F32: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.EqF32, + module.binary(BinaryOp.SubF32, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F32) + ), + module.f32(0) + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, opName, type.toString() + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f32); + let ret = module.binary(BinaryOp.EqF32, + module.binary(BinaryOp.SubF32, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F32) + ), + module.f32(0) ); - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], - compiler.options.usizeType, - Constraints.CONV_IMPLICIT - ); - let arg1 = isAsm - ? compiler.compileExpression(operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F64: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.EqF64, + module.binary(BinaryOp.SubF64, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F64) + ), + module.f64(0) ); - let inType = compiler.currentType; - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] + } + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f64); + let ret = module.binary(BinaryOp.EqF64, + module.binary(BinaryOp.SubF64, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F64) + ), + module.f64(0) ); - inType = type; - } - let immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = inType; - return module.unreachable(); + flow.freeTempLocal(temp); + return ret; } - let op: AtomicRMWOp; - switch (prototype.internalName) { - default: assert(false); - case BuiltinNames.atomic_add: { op = AtomicRMWOp.Add; break; } - case BuiltinNames.atomic_sub: { op = AtomicRMWOp.Sub; break; } - case BuiltinNames.atomic_and: { op = AtomicRMWOp.And; break; } - case BuiltinNames.atomic_or: { op = AtomicRMWOp.Or; break; } - case BuiltinNames.atomic_xor: { op = AtomicRMWOp.Xor; break; } - case BuiltinNames.atomic_xchg: { op = AtomicRMWOp.Xchg; break; } - } - compiler.currentType = inType; - return module.atomic_rmw(op, type.byteSize, immOffset, arg0, arg1, inType.toNativeType()); } - case BuiltinNames.atomic_cmpxchg: { // cmpxchg(ptr: usize, expected: T, replacement: T, off?: usize) -> T - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 3, 4, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.INTEGER) || type.size < 8) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.cmpxchg", type.toString() - ); - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], - compiler.options.usizeType, - Constraints.CONV_IMPLICIT + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "isFinite", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.isFinite, builtin_isFinite); + +// === Memory access ========================================================================== + +// load(offset: usize, immOffset?: usize, immAlign?: usize) -> T* +function builtin_load(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + var outType = ( + contextualType != Type.auto && + type.is(TypeFlags.INTEGER) && + contextualType.is(TypeFlags.INTEGER) && + contextualType.size > type.size + ) ? contextualType : type; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var numOperands = operands.length; + var immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = outType; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (numOperands == 3) { + immAlign = evaluateImmediateOffset(operands[2], compiler); + if (immAlign < 0) { + compiler.currentType = outType; + return module.unreachable(); + } + if (immAlign > naturalAlign) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() ); - let arg1 = isAsm - ? compiler.compileExpression(operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT - ); - let inType = compiler.currentType; - let arg2 = compiler.compileExpression(operands[2], - inType, + compiler.currentType = outType; + return module.unreachable(); + } + if (!isPowerOf2(immAlign)) { + compiler.error( + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" + ); + compiler.currentType = outType; + return module.unreachable(); + } + } else { + immAlign = naturalAlign; + } + compiler.currentType = outType; + return module.load( + type.byteSize, + type.is(TypeFlags.SIGNED | TypeFlags.INTEGER), + arg0, + outType.toNativeType(), + immOffset, + immAlign + ); +} +builtins.set(BuiltinNames.load, builtin_load); + +// store(offset: usize, value: T*, offset?: usize, align?: usize) -> void +function builtin_store(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkTypeRequired(ctx) | + checkArgsOptional(ctx, 2, 4) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = ctx.isAsm + ? compiler.compileExpression(operands[1], + contextualType, Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT ); - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] - ); - arg2 = compiler.convertExpression(arg2, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[2] - ); - inType = type; - } - let immOffset = operands.length == 4 ? evaluateImmediateOffset(operands[3], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = inType; - return module.unreachable(); - } - compiler.currentType = inType; - return module.atomic_cmpxchg(type.byteSize, immOffset, arg0, arg1, arg2, inType.toNativeType()); + var inType = compiler.currentType; + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + inType = type; + } + var immOffset = operands.length >= 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.void; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (operands.length == 4) { + immAlign = evaluateImmediateOffset(operands[3], compiler); + if (immAlign < 0) { + compiler.currentType = Type.void; + return module.unreachable(); } - case BuiltinNames.atomic_wait: { // wait(ptr: usize, expected: T, timeout: i64) -> i32 - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) { - compiler.currentType = Type.i32; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.i64, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.i32; - switch (type.kind) { - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: return module.atomic_wait(arg0, arg1, arg2, type.toNativeType()); - } + if (immAlign > naturalAlign) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.wait", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[3].range, "Alignment", "0", naturalAlign.toString() ); + compiler.currentType = Type.void; return module.unreachable(); } - case BuiltinNames.atomic_notify: { // notify(ptr: usize, count: i32) -> i32 - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.i32; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.i32; - return module.atomic_notify(arg0, arg1); - } - case BuiltinNames.atomic_fence: { // fence() -> void + if (!isPowerOf2(immAlign)) { + compiler.error( + DiagnosticCode._0_must_be_a_power_of_two, + operands[3].range, "Alignment" + ); compiler.currentType = Type.void; - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - return module.atomic_fence(); + return module.unreachable(); } + } else { + immAlign = naturalAlign; + } + compiler.currentType = Type.void; + return module.store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset, immAlign); +} +builtins.set(BuiltinNames.store, builtin_store); + +// === Atomics ================================================================================ + +// atomic.load(offset: usize, immOffset?: usize) -> T* +function builtin_atomic_load(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + var outType = ( + type.is(TypeFlags.INTEGER) && + contextualType.is(TypeFlags.INTEGER) && + contextualType.size > type.size + ) ? contextualType : type; + if (!type.is(TypeFlags.INTEGER)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.load", type.toString() + ); + compiler.currentType = outType; + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var immOffset = operands.length == 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = outType; + return module.unreachable(); + } + compiler.currentType = outType; + return module.atomic_load( + type.byteSize, + arg0, + outType.toNativeType(), + immOffset + ); +} +builtins.set(BuiltinNames.atomic_load, builtin_atomic_load); + +// atomic.store(offset: usize, value: T*, immOffset?: usize) -> void +function builtin_atomic_store(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + if (!type.is(TypeFlags.INTEGER)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.store", type.toString() + ); + compiler.currentType = Type.void; + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = ctx.isAsm + ? compiler.compileExpression( + operands[1], + contextualType, + Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT + ); + var inType = compiler.currentType; + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + inType = type; + } + var immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.void; + return module.unreachable(); + } + compiler.currentType = Type.void; + return module.atomic_store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset); +} +builtins.set(BuiltinNames.atomic_store, builtin_atomic_store); + +// any_atomic_binary(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_binary(ctx: BuiltinContext, op: AtomicRMWOp, opName: string): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + if (!type.is(TypeFlags.INTEGER) || type.size < 8) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, opName, type.toString() + ); + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], + compiler.options.usizeType, + Constraints.CONV_IMPLICIT + ); + var arg1 = ctx.isAsm + ? compiler.compileExpression(operands[1], + contextualType, + Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT + ); + var inType = compiler.currentType; + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + inType = type; + } + var immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = inType; + return module.unreachable(); + } + compiler.currentType = inType; + return module.atomic_rmw(op, type.byteSize, immOffset, arg0, arg1, inType.toNativeType()); +} + +// atomic.add(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_add(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Add, "atomic.add"); +} +builtins.set(BuiltinNames.atomic_add, builtin_atomic_add); + +// atomic.sub(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_sub(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Sub, "atomic.sub"); +} +builtins.set(BuiltinNames.atomic_sub, builtin_atomic_sub); + +// atomic.and(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_and(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.And, "atomic.and"); +} +builtins.set(BuiltinNames.atomic_and, builtin_atomic_and); + +// atomic.or(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_or(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Or, "atomic.or"); +} +builtins.set(BuiltinNames.atomic_or, builtin_atomic_or); + +// atomic.xor(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_xor(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Xor, "atomic.xor"); +} +builtins.set(BuiltinNames.atomic_xor, builtin_atomic_xor); + +// atomic.xchg(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_xchg(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Xchg, "atomic.xchg"); +} +builtins.set(BuiltinNames.atomic_xchg, builtin_atomic_xchg); + +// atomic.cmpxchg(ptr: usize, expected: T, replacement: T, off?: usize) -> T +function builtin_atomic_cmpxchg(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 3, 4) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + if (!type.is(TypeFlags.INTEGER) || type.size < 8) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.cmpxchg", type.toString() + ); + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], + compiler.options.usizeType, + Constraints.CONV_IMPLICIT + ); + var arg1 = ctx.isAsm + ? compiler.compileExpression(operands[1], + contextualType, + Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT + ); + var inType = compiler.currentType; + var arg2 = compiler.compileExpression(operands[2], + inType, + Constraints.CONV_IMPLICIT + ); + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + arg2 = compiler.convertExpression(arg2, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[2] + ); + inType = type; + } + var immOffset = operands.length == 4 ? evaluateImmediateOffset(operands[3], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = inType; + return module.unreachable(); + } + compiler.currentType = inType; + return module.atomic_cmpxchg(type.byteSize, immOffset, arg0, arg1, arg2, inType.toNativeType()); +} +builtins.set(BuiltinNames.atomic_cmpxchg, builtin_atomic_cmpxchg); + +// atomic.wait(ptr: usize, expected: T, timeout: i64) -> i32 +function builtin_atomic_wait(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.i32; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.i64, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.i32; + switch (type.kind) { + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: return module.atomic_wait(arg0, arg1, arg2, type.toNativeType()); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.wait", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.atomic_wait, builtin_atomic_wait); + +// atomic.notify(ptr: usize, count: i32) -> i32 +function builtin_atomic_notify(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.i32; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.i32; + return module.atomic_notify(arg0, arg1); +} +builtins.set(BuiltinNames.atomic_notify, builtin_atomic_notify); + +// atomic.fence() -> void +function builtin_atomic_fence(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + return module.atomic_fence(); +} +builtins.set(BuiltinNames.atomic_fence, builtin_atomic_fence); + +// === Control flow =========================================================================== + +// select(ifTrue: T, ifFalse: T, condition: bool) -> T +function builtin_select(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto); + var type = compiler.currentType; + if (!type.isAny(TypeFlags.VALUE | TypeFlags.REFERENCE)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "select", type.toString() + ); + return module.unreachable(); + } + var arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + var arg2 = compiler.makeIsTrueish( + compiler.compileExpression(operands[2], Type.bool), + compiler.currentType // ^ + ); + compiler.currentType = type; + return module.select(arg0, arg1, arg2); +} +builtins.set(BuiltinNames.select, builtin_select); - // === Control flow =========================================================================== +// unreachable() -> * +function builtin_unreachable(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + checkArgsRequired(ctx, 0); + return ctx.compiler.module.unreachable(); +} +builtins.set(BuiltinNames.unreachable, builtin_unreachable); - case BuiltinNames.select: { // select(ifTrue: T, ifFalse: T, condition: bool) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto); - let type = compiler.currentType; - if (!type.isAny(TypeFlags.VALUE | TypeFlags.REFERENCE)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "select", type.toString() - ); - return module.unreachable(); - } - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - let arg2 = compiler.makeIsTrueish( - compiler.compileExpression(operands[2], Type.bool), - compiler.currentType // ^ - ); - compiler.currentType = type; - return module.select(arg0, arg1, arg2); - } - case BuiltinNames.unreachable: { // unreachable() -> * - if (typeArguments) { - compiler.error( - DiagnosticCode.Type_0_is_not_generic, - reportNode.typeArgumentsRange, prototype.internalName - ); - } - checkArgsRequired(operands, 0, reportNode, compiler); - return module.unreachable(); - } +// === Memory ================================================================================= - // === Memory ================================================================================= +// memory.size() -> i32 +function builtin_memory_size(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.i32; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + return module.host(HostOp.MemorySize); +} +builtins.set(BuiltinNames.memory_size, builtin_memory_size); - case BuiltinNames.memory_size: { // memory.size() -> i32 - compiler.currentType = Type.i32; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - return module.host(HostOp.MemorySize); - } - case BuiltinNames.memory_grow: { // memory.grow(pages: i32) -> i32 - compiler.currentType = Type.i32; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - return module.host(HostOp.MemoryGrow, null, [ - compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT) - ]); - } - case BuiltinNames.memory_copy: { // memory.copy(dest: usize, src: usize: n: usize) -> void - compiler.currentType = Type.void; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) return module.unreachable(); - if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { - // use stdlib alternative if not supported - let instance = compiler.resolver.resolveFunction(prototype, null); // reports - compiler.currentType = Type.void; - if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); - return compiler.compileCallDirect(instance, operands, reportNode); - } - let usizeType = compiler.options.usizeType; - let arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], usizeType, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.void; - return module.memory_copy(arg0, arg1, arg2); - } - case BuiltinNames.memory_fill: { // memory.fill(dest: usize, value: u8, n: usize) -> void - compiler.currentType = Type.void; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) return module.unreachable(); - if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { - // use stdlib alternative if not supported - let instance = compiler.resolver.resolveFunction(prototype, null); // reports - compiler.currentType = Type.void; - if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); - return compiler.compileCallDirect(instance, operands, reportNode); - } - let usizeType = compiler.options.usizeType; - let arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.void; - return module.memory_fill(arg0, arg1, arg2); - } +// memory.grow(pages: i32) -> i32 +function builtin_memory_grow(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.i32; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + return module.host(HostOp.MemoryGrow, null, [ + compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT) + ]); +} +builtins.set(BuiltinNames.memory_grow, builtin_memory_grow); - // === Helpers ================================================================================ +// memory.copy(dest: usize, src: usize: n: usize) -> void +function builtin_memory_copy(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + var operands = ctx.operands; + if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { + // use stdlib alternative if not supported + let instance = compiler.resolver.resolveFunction(ctx.prototype, null); // reports + compiler.currentType = Type.void; + if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); + return compiler.compileCallDirect(instance, operands, ctx.reportNode); + } + var usizeType = compiler.options.usizeType; + var arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], usizeType, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.void; + return module.memory_copy(arg0, arg1, arg2); +} +builtins.set(BuiltinNames.memory_copy, builtin_memory_copy); - case BuiltinNames.changetype: { // changetype(value: *) -> T - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let toType = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.auto); - let fromType = compiler.currentType; - compiler.currentType = toType; - if (!fromType.isChangeableTo(toType)) { - compiler.error( - DiagnosticCode.Type_0_cannot_be_changed_to_type_1, - reportNode.range, fromType.toString(), toType.toString() - ); - return module.unreachable(); - } - return arg0; - } - case BuiltinNames.assert: { // assert(isTrueish: T, message?: string) -> T{!= null} - if ( - checkTypeOptional(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 1, 2, reportNode, compiler) - ) { - if (typeArguments) { - assert(typeArguments.length); // otherwise invalid, should not been set at all - compiler.currentType = typeArguments[0].nonNullableType; - } - return module.unreachable(); - } - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.bool, Constraints.MUST_WRAP); - let type = compiler.currentType; - compiler.currentType = type.nonNullableType; - - // if the assertion can be proven statically, omit it - if (getExpressionId(arg0 = module.precomputeExpression(arg0)) == ExpressionId.Const) { - switch (getExpressionType(arg0)) { - case NativeType.I32: { - if (getConstValueI32(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - case NativeType.I64: { - if (getConstValueI64Low(arg0) != 0 || getConstValueI64High(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - case NativeType.F32: { - if (getConstValueF32(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - case NativeType.F64: { - if (getConstValueF64(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; +// memory.fill(dest: usize, value: u8, n: usize) -> void +function builtin_memory_fill(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + var operands = ctx.operands; + if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { + // use stdlib alternative if not supported + let instance = compiler.resolver.resolveFunction(ctx.prototype, null); // reports + compiler.currentType = Type.void; + if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); + return compiler.compileCallDirect(instance, operands, ctx.reportNode); + } + var usizeType = compiler.options.usizeType; + var arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.void; + return module.memory_fill(arg0, arg1, arg2); +} +builtins.set(BuiltinNames.memory_fill, builtin_memory_fill); + +// === Helpers ================================================================================ + +// changetype(value: *) -> T +function builtin_changetype(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = assert(ctx.typeArguments); + var toType = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.auto); + var fromType = compiler.currentType; + compiler.currentType = toType; + if (!fromType.isChangeableTo(toType)) { + compiler.error( + DiagnosticCode.Type_0_cannot_be_changed_to_type_1, + ctx.reportNode.range, fromType.toString(), toType.toString() + ); + return module.unreachable(); + } + return arg0; +} +builtins.set(BuiltinNames.changetype, builtin_changetype); + +// assert(isTrueish: T, message?: string) -> T{!= null} +function builtin_assert(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var typeArguments = ctx.typeArguments; + if ( + checkTypeOptional(ctx, true) | + checkArgsOptional(ctx, 1, 2) + ) { + if (typeArguments) { + assert(typeArguments.length); // otherwise invalid, should not been set at all + compiler.currentType = typeArguments[0].nonNullableType; + } + return module.unreachable(); + } + var operands = ctx.operands; + var contextualType = ctx.contextualType; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.bool, Constraints.MUST_WRAP); + var type = compiler.currentType; + compiler.currentType = type.nonNullableType; + + // if the assertion can be proven statically, omit it + if (getExpressionId(arg0 = module.precomputeExpression(arg0)) == ExpressionId.Const) { + switch (getExpressionType(arg0)) { + case NativeType.I32: { + if (getConstValueI32(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); } + return arg0; } + break; } - - // return ifTrueish if assertions are disabled - if (compiler.options.noAssert) { - if (contextualType == Type.void) { // simplify if dropped anyway - compiler.currentType = Type.void; - return module.nop(); + case NativeType.I64: { + if (getConstValueI64Low(arg0) != 0 || getConstValueI64High(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); + } + return arg0; } - return arg0; + break; } - - // otherwise call abort if the assertion is false-ish - let abort = compiler.makeAbort(operands.length == 2 ? operands[1] : null, reportNode); - compiler.currentType = type.nonNullableType; - if (contextualType == Type.void) { // simplify if dropped anyway - compiler.currentType = Type.void; - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: return module.if(module.unary(UnaryOp.EqzI32, arg0), abort); - case TypeKind.I64: - case TypeKind.U64: return module.if(module.unary(UnaryOp.EqzI64, arg0), abort); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.if( - module.unary( - compiler.options.isWasm64 - ? UnaryOp.EqzI64 - : UnaryOp.EqzI32, - arg0 - ), - abort - ); + case NativeType.F32: { + if (getConstValueF32(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); } - // TODO: also check for NaN in float assertions, as in `Boolean(NaN) -> false`? - case TypeKind.F32: return module.if(module.binary(BinaryOp.EqF32, arg0, module.f32(0)), abort); - case TypeKind.F64: return module.if(module.binary(BinaryOp.EqF64, arg0, module.f64(0)), abort); + return arg0; } - } else { - compiler.currentType = type.nonNullableType; - let flow = compiler.currentFlow; - switch (compiler.currentType.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: { - let temp = flow.getTempLocal(type); - flow.setLocalFlag(temp.index, LocalFlags.WRAPPED); // arg0 is wrapped - let ret = module.if( - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.I32), - abort - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.I64: - case TypeKind.U64: { - let temp = flow.getTempLocal(Type.i64); - let ret = module.if( - module.unary(UnaryOp.EqzI64, - module.local_tee(temp.index, arg0) - ), - abort, - module.local_get(temp.index, NativeType.I64) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.ISIZE: - case TypeKind.USIZE: { - let temp = flow.getTempLocal(compiler.options.usizeType); - let ret = module.if( - module.unary( - compiler.options.isWasm64 - ? UnaryOp.EqzI64 - : UnaryOp.EqzI32, - module.local_tee(temp.index, arg0) - ), - abort, - module.local_get(temp.index, compiler.options.nativeSizeType) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F32: { - let temp = flow.getTempLocal(Type.f32); - let ret = module.if( - module.binary(BinaryOp.EqF32, - module.local_tee(temp.index, arg0), - module.f32(0) - ), - abort, - module.local_get(temp.index, NativeType.F32) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F64: { - let temp = flow.getTempLocal(Type.f64); - let ret = module.if( - module.binary(BinaryOp.EqF64, - module.local_tee(temp.index, arg0), - module.f64(0) - ), - abort, - module.local_get(temp.index, NativeType.F64) - ); - flow.freeTempLocal(temp); - return ret; + break; + } + case NativeType.F64: { + if (getConstValueF64(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); } + return arg0; } + break; } - compiler.error( - DiagnosticCode.Not_implemented, - reportNode.typeArgumentsRange - ); - return abort; - } - case BuiltinNames.unchecked: { // unchecked(expr: *) -> * - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let flow = compiler.currentFlow; - let alreadyUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT); - flow.set(FlowFlags.UNCHECKED_CONTEXT); - // eliminate unnecessary tees by preferring contextualType(=void) - let expr = compiler.compileExpression(operands[0], contextualType); - if (!alreadyUnchecked) flow.unset(FlowFlags.UNCHECKED_CONTEXT); - return expr; - } - case BuiltinNames.instantiate: { // instantiate(...args: *[]) -> T - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) - ) return module.unreachable(); - let typeArgument = typeArguments![0]; - let classInstance = typeArgument.classReference; - if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) { - compiler.error( - DiagnosticCode.This_expression_is_not_constructable, - reportNode.expression.range - ); - return module.unreachable(); - } - compiler.currentType = classInstance.type; - return compiler.compileInstantiate(classInstance, operands, Constraints.NONE, reportNode); } + } - // === User-defined diagnostics =============================================================== - - case BuiltinNames.ERROR: { - checkTypeAbsent(typeArguments, reportNode, prototype); - compiler.error( - DiagnosticCode.User_defined_0, - reportNode.range, (operands.length ? operands[0] : reportNode).range.toString() - ); - return module.unreachable(); - } - case BuiltinNames.WARNING: { - checkTypeAbsent(typeArguments, reportNode, prototype); - compiler.warning( - DiagnosticCode.User_defined_0, - reportNode.range, (operands.length ? operands[0] : reportNode).range.toString() - ); - return module.nop(); - } - case BuiltinNames.INFO: { - checkTypeAbsent(typeArguments, reportNode, prototype); - compiler.info( - DiagnosticCode.User_defined_0, - reportNode.range, (operands.length ? operands[0] : reportNode).range.toString() - ); + // return ifTrueish if assertions are disabled + if (compiler.options.noAssert) { + if (contextualType == Type.void) { // simplify if dropped anyway + compiler.currentType = Type.void; return module.nop(); } + return arg0; + } - // === Portable type conversions ============================================================== - - case BuiltinNames.i8: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i8; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i8, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.i16: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i16; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i16, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.i32: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i32; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.i64: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i64; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i64, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.isize: { - let isizeType = compiler.options.isizeType; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = isizeType; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], isizeType, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u8: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u8; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u8, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u16: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u16; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u16, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u32: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u32; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u32, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u64: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u64; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u64, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.usize: { - let usizeType = compiler.options.usizeType; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = usizeType; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], usizeType, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.bool: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); + // otherwise call abort if the assertion is false-ish + var abort = compiler.makeAbort(operands.length == 2 ? operands[1] : null, ctx.reportNode); + compiler.currentType = type.nonNullableType; + if (contextualType == Type.void) { // simplify if dropped anyway + compiler.currentType = Type.void; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: return module.if(module.unary(UnaryOp.EqzI32, arg0), abort); + case TypeKind.I64: + case TypeKind.U64: return module.if(module.unary(UnaryOp.EqzI64, arg0), abort); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.if( + module.unary( + compiler.options.isWasm64 + ? UnaryOp.EqzI64 + : UnaryOp.EqzI32, + arg0 + ), + abort + ); } - return compiler.compileExpression(operands[0], Type.bool, Constraints.CONV_EXPLICIT); + // TODO: also check for NaN in float assertions, as in `Boolean(NaN) -> false`? + case TypeKind.F32: return module.if(module.binary(BinaryOp.EqF32, arg0, module.f32(0)), abort); + case TypeKind.F64: return module.if(module.binary(BinaryOp.EqF64, arg0, module.f64(0)), abort); } - case BuiltinNames.f32: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.f32; - return module.unreachable(); + } else { + compiler.currentType = type.nonNullableType; + let flow = compiler.currentFlow; + switch (compiler.currentType.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: { + let temp = flow.getTempLocal(type); + flow.setLocalFlag(temp.index, LocalFlags.WRAPPED); // arg0 is wrapped + let ret = module.if( + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.I32), + abort + ); + flow.freeTempLocal(temp); + return ret; } - return compiler.compileExpression(operands[0], Type.f32, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.f64: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.f64; - return module.unreachable(); + case TypeKind.I64: + case TypeKind.U64: { + let temp = flow.getTempLocal(Type.i64); + let ret = module.if( + module.unary(UnaryOp.EqzI64, + module.local_tee(temp.index, arg0) + ), + abort, + module.local_get(temp.index, NativeType.I64) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + let temp = flow.getTempLocal(compiler.options.usizeType); + let ret = module.if( + module.unary( + compiler.options.isWasm64 + ? UnaryOp.EqzI64 + : UnaryOp.EqzI32, + module.local_tee(temp.index, arg0) + ), + abort, + module.local_get(temp.index, compiler.options.nativeSizeType) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F32: { + let temp = flow.getTempLocal(Type.f32); + let ret = module.if( + module.binary(BinaryOp.EqF32, + module.local_tee(temp.index, arg0), + module.f32(0) + ), + abort, + module.local_get(temp.index, NativeType.F32) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F64: { + let temp = flow.getTempLocal(Type.f64); + let ret = module.if( + module.binary(BinaryOp.EqF64, + module.local_tee(temp.index, arg0), + module.f64(0) + ), + abort, + module.local_get(temp.index, NativeType.F64) + ); + flow.freeTempLocal(temp); + return ret; } - return compiler.compileExpression(operands[0], Type.f64, Constraints.CONV_EXPLICIT); } + } + compiler.error( + DiagnosticCode.Not_implemented, + ctx.reportNode.typeArgumentsRange + ); + return abort; +} +builtins.set(BuiltinNames.assert, builtin_assert); + +// unchecked(expr: *) -> * +function builtin_unchecked(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var flow = compiler.currentFlow; + var alreadyUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT); + flow.set(FlowFlags.UNCHECKED_CONTEXT); + // eliminate unnecessary tees by preferring contextualType(=void) + var expr = compiler.compileExpression(ctx.operands[0], ctx.contextualType); + if (!alreadyUnchecked) flow.unset(FlowFlags.UNCHECKED_CONTEXT); + return expr; +} +builtins.set(BuiltinNames.unchecked, builtin_unchecked); + +// instantiate(...args: *[]) -> T +function builtin_instantiate(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = assert(ctx.typeArguments); + var typeArgument = typeArguments[0]; + var classInstance = typeArgument.classReference; + if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) { + compiler.error( + DiagnosticCode.This_expression_is_not_constructable, + ctx.reportNode.expression.range + ); + return module.unreachable(); + } + compiler.currentType = classInstance.type; + return compiler.compileInstantiate(classInstance, operands, Constraints.NONE, ctx.reportNode); +} +builtins.set(BuiltinNames.instantiate, builtin_instantiate); + +// === User-defined diagnostics =============================================================== + +function builtin_diagnostic(ctx: BuiltinContext, category: DiagnosticCategory): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + checkTypeAbsent(ctx); + var operands = ctx.operands; + var reportNode = ctx.reportNode; + compiler.emitDiagnostic( + DiagnosticCode.User_defined_0, + category, + reportNode.range, + null, + operands.length + ? operands[0].range.toString() + : reportNode.range.toString() + ); + return category == DiagnosticCategory.ERROR + ? module.unreachable() + : module.nop(); +} + +// ERROR(message?) +function builtin_error(ctx: BuiltinContext): ExpressionRef { + return builtin_diagnostic(ctx, DiagnosticCategory.ERROR); +} +builtins.set(BuiltinNames.ERROR, builtin_error); - // === SIMD =================================================================================== +// WARNING(message?) +function builtin_warning(ctx: BuiltinContext): ExpressionRef { + return builtin_diagnostic(ctx, DiagnosticCategory.WARNING); +} +builtins.set(BuiltinNames.WARNING, builtin_warning); - case BuiltinNames.v128: // alias for now - case BuiltinNames.i8x16: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 16, reportNode, compiler) - ) { +// INFO(message?) +function builtin_info(ctx: BuiltinContext): ExpressionRef { + return builtin_diagnostic(ctx, DiagnosticCategory.INFO); +} +builtins.set(BuiltinNames.INFO, builtin_info); + +// === Portable type conversions ============================================================== + +function builtin_conversion(ctx: BuiltinContext, toType: Type): ExpressionRef { + var compiler = ctx.compiler; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = toType; + return compiler.module.unreachable(); + } + return compiler.compileExpression(ctx.operands[0], toType, Constraints.CONV_EXPLICIT); +} + +// i8(*) -> i8 +function builtin_i8(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i8); +} +builtins.set(BuiltinNames.i8, builtin_i8); + +// i16(*) -> i16 +function builtin_i16(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i16); +} +builtins.set(BuiltinNames.i16, builtin_i16); + +// i32(*) -> i32 +function builtin_i32(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i32); +} +builtins.set(BuiltinNames.i32, builtin_i32); + +// i64(*) -> i64 +function builtin_i64(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i64); +} +builtins.set(BuiltinNames.i64, builtin_i64); + +// isize(*) -> isize +function builtin_isize(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, ctx.compiler.options.isizeType); +} +builtins.set(BuiltinNames.isize, builtin_isize); + +// u8(*) -> u8 +function builtin_u8(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u8); +} +builtins.set(BuiltinNames.u8, builtin_u8); + +// u16(*) -> u16 +function builtin_u16(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u16); +} +builtins.set(BuiltinNames.u16, builtin_u16); + +// u32(*) -> u32 +function builtin_u32(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u32); +} +builtins.set(BuiltinNames.u32, builtin_u32); + +// u64(*) -> u64 +function builtin_u64(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u64); +} +builtins.set(BuiltinNames.u64, builtin_u64); + +// usize(*) -> usize +function builtin_usize(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, ctx.compiler.options.usizeType); +} +builtins.set(BuiltinNames.usize, builtin_usize); + +// bool(*) -> bool +function builtin_bool(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.bool); +} +builtins.set(BuiltinNames.bool, builtin_bool); + +// f32(*) -> f32 +function builtin_f32(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.f32); +} +builtins.set(BuiltinNames.f32, builtin_f32); + +// f64(*) -> f64 +function builtin_f64(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.f64); +} +builtins.set(BuiltinNames.f64, builtin_f64); + +// TODO: alias for now, splat input integer perhaps? +function builtin_v128(ctx: BuiltinContext): ExpressionRef { + return builtin_i8x16(ctx); +} +builtins.set(BuiltinNames.v128, builtin_v128); + +// === SIMD =================================================================================== + +// i8x16(...values: i8[16]) -> v128 +function builtin_i8x16(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 16) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 16; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i8, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); compiler.currentType = Type.v128; return module.unreachable(); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 16; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i8, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.I32); - writeI8(getConstValueI32(expr), bytes, i); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); + assert(getExpressionType(expr) == NativeType.I32); + writeI8(getConstValueI32(expr), bytes, i); } - case BuiltinNames.i16x8: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 8, reportNode, compiler) - ) { + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i8x16, builtin_i8x16); + +// i16x8(...values: i16[8]) -> v128 +function builtin_i16x8(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 8) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 8; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i16, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); compiler.currentType = Type.v128; return module.unreachable(); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 8; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i16, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.I32); - writeI16(getConstValueI32(expr), bytes, i << 1); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); + assert(getExpressionType(expr) == NativeType.I32); + writeI16(getConstValueI32(expr), bytes, i << 1); } - case BuiltinNames.i32x4: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 4, reportNode, compiler) - ) { + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i16x8, builtin_i16x8); + +// i32x4(...values: i32[4]) -> v128 +function builtin_i32x4(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 4) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 4; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i32, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); compiler.currentType = Type.v128; return module.unreachable(); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 4; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i32, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.I32); - writeI32(getConstValueI32(expr), bytes, i << 2); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); + assert(getExpressionType(expr) == NativeType.I32); + writeI32(getConstValueI32(expr), bytes, i << 2); } - case BuiltinNames.i64x2: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i32x4, builtin_i32x4); + +// i64x2(...values: i64[2]) -> v128 +function builtin_i64x2(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 2; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i64, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); compiler.currentType = Type.v128; return module.unreachable(); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 2; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i64, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.I64); - let off = i << 3; - writeI32(getConstValueI64Low(expr), bytes, off); - writeI32(getConstValueI64High(expr), bytes, off + 4); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); + assert(getExpressionType(expr) == NativeType.I64); + let off = i << 3; + writeI32(getConstValueI64Low(expr), bytes, off); + writeI32(getConstValueI64High(expr), bytes, off + 4); } - case BuiltinNames.f32x4: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 4, reportNode, compiler) - ) { + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i64x2, builtin_i64x2); + +// f32x4(...values: f32[4]) -> v128 +function builtin_f32x4(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 4) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 4; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.f32, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); compiler.currentType = Type.v128; return module.unreachable(); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 4; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.f32, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.F32); - writeF32(getConstValueF32(expr), bytes, i << 2); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); + assert(getExpressionType(expr) == NativeType.F32); + writeF32(getConstValueF32(expr), bytes, i << 2); } - case BuiltinNames.f64x2: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.f32x4, builtin_f32x4); + +// f64x2(...values: f64[2]) -> v128 +function builtin_f64x2(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 2; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.f64, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); compiler.currentType = Type.v128; return module.unreachable(); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 2; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.f64, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.F64); - writeF64(getConstValueF64(expr), bytes, i << 3); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); + assert(getExpressionType(expr) == NativeType.F64); + writeF64(getConstValueF64(expr), bytes, i << 3); } + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.f64x2, builtin_f64x2); + +/** Compiles a call to a built-in function. */ +export function compileCall( + /* Compiler reference. */ + compiler: Compiler, + /** Respective function prototype. */ + prototype: FunctionPrototype, + /** Pre-resolved type arguments. */ + typeArguments: Type[] | null, + /** Operand expressions. */ + operands: Expression[], + /** Contextual type. */ + contextualType: Type, + /** Respective call expression. */ + reportNode: CallExpression, + /** Indicates that contextual type is ASM type. */ + isAsm: bool = false +): ExpressionRef { + + // TODO: call this from the compiler and cache ctx + var ctx = new BuiltinContext(); + ctx.compiler = compiler; + ctx.prototype = prototype; + ctx.typeArguments = typeArguments; + ctx.operands = operands; + ctx.contextualType = contextualType; + ctx.reportNode = reportNode; + ctx.isAsm = isAsm; + + // Handle registered builtin + var internalName = prototype.internalName; + if (builtins.has(internalName)) { + let fn = builtins.get(internalName)!; + return fn(ctx); + } + + // Fall back to legacy builtins (TODO: port 'em all) + var module = compiler.module; + + switch (prototype.internalName) { + + // === SIMD =================================================================================== + case BuiltinNames.v128_splat: { // splat(x: T) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -2657,9 +3234,9 @@ export function compileCall( } case BuiltinNames.v128_extract_lane: { // extract_lane(x: v128, idx: u8) -> T if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 2) ) return module.unreachable(); let type = typeArguments![0]; let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); @@ -2714,9 +3291,9 @@ export function compileCall( } case BuiltinNames.v128_replace_lane: { // replace_lane(x: v128, idx: u8, value: T) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -2775,8 +3352,8 @@ export function compileCall( } case BuiltinNames.v128_shuffle: { // shuffle(a: v128, b: v128, ...lanes: u8[]) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -2787,7 +3364,7 @@ export function compileCall( let laneCount = 16 / laneWidth; assert(isInteger(laneCount) && isPowerOf2(laneCount)); if ( - checkArgsRequired(operands, 2 + laneCount, reportNode, compiler) + checkArgsRequired(ctx, 2 + laneCount) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -2881,9 +3458,9 @@ export function compileCall( } case BuiltinNames.v128_swizzle: { // swizzle(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -2894,9 +3471,9 @@ export function compileCall( } case BuiltinNames.v128_load_splat: { // load_splat(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 3, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) ) return module.unreachable(); let type = typeArguments![0]; let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); @@ -2969,9 +3546,9 @@ export function compileCall( } case BuiltinNames.v128_load_ext: { // load_ext(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 3, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) ) return module.unreachable(); let type = typeArguments![0]; let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); @@ -3033,9 +3610,9 @@ export function compileCall( } case BuiltinNames.v128_add: { // add(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3074,9 +3651,9 @@ export function compileCall( } case BuiltinNames.v128_sub: { // sub(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3115,9 +3692,9 @@ export function compileCall( } case BuiltinNames.v128_mul: { // mul(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3152,9 +3729,9 @@ export function compileCall( } case BuiltinNames.v128_div: { // div(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3176,9 +3753,9 @@ export function compileCall( } case BuiltinNames.v128_add_saturate: { // add_saturate(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3202,9 +3779,9 @@ export function compileCall( } case BuiltinNames.v128_sub_saturate: { // sub_saturate(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3228,9 +3805,9 @@ export function compileCall( } case BuiltinNames.v128_min: { // min(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3266,9 +3843,9 @@ export function compileCall( } case BuiltinNames.v128_max: { // max(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3304,9 +3881,9 @@ export function compileCall( } case BuiltinNames.v128_dot: { // dot(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3327,9 +3904,9 @@ export function compileCall( } case BuiltinNames.v128_avgr: { // avgr(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3351,9 +3928,9 @@ export function compileCall( } case BuiltinNames.v128_eq: { // eq(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3388,9 +3965,9 @@ export function compileCall( } case BuiltinNames.v128_ne: { // ne(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3425,9 +4002,9 @@ export function compileCall( } case BuiltinNames.v128_lt: { // lt(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3467,9 +4044,9 @@ export function compileCall( } case BuiltinNames.v128_le: { // le(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3509,9 +4086,9 @@ export function compileCall( } case BuiltinNames.v128_gt: { // gt(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3551,9 +4128,9 @@ export function compileCall( } case BuiltinNames.v128_ge: { // ge(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3593,9 +4170,9 @@ export function compileCall( } case BuiltinNames.v128_narrow: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3619,9 +4196,9 @@ export function compileCall( } case BuiltinNames.v128_neg: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3659,9 +4236,9 @@ export function compileCall( } case BuiltinNames.v128_abs: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3682,9 +4259,9 @@ export function compileCall( } case BuiltinNames.v128_sqrt: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3705,9 +4282,9 @@ export function compileCall( } case BuiltinNames.v128_convert: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3730,9 +4307,9 @@ export function compileCall( } case BuiltinNames.v128_trunc_sat: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3755,9 +4332,9 @@ export function compileCall( } case BuiltinNames.v128_widen_low: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3780,9 +4357,9 @@ export function compileCall( } case BuiltinNames.v128_widen_high: { if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3805,9 +4382,9 @@ export function compileCall( } case BuiltinNames.v128_shl: { // shl(a: v128, b: i32) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3845,9 +4422,9 @@ export function compileCall( } case BuiltinNames.v128_shr: { // shr(a: v128, b: i32) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3892,9 +4469,9 @@ export function compileCall( } case BuiltinNames.v128_and: { // and(a: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3905,9 +4482,9 @@ export function compileCall( } case BuiltinNames.v128_or: { // or(a: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3918,9 +4495,9 @@ export function compileCall( } case BuiltinNames.v128_xor: { // xor(a: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3931,9 +4508,9 @@ export function compileCall( } case BuiltinNames.v128_andnot: { // andnot(a: v128, b: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3944,9 +4521,9 @@ export function compileCall( } case BuiltinNames.v128_not: { // not(a: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3956,9 +4533,9 @@ export function compileCall( } case BuiltinNames.v128_bitselect: { // bitselect(v1: v128, v2: v128, c: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 3, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -3970,9 +4547,9 @@ export function compileCall( } case BuiltinNames.v128_any_true: { // any_true(a: v128) -> bool if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.bool; return module.unreachable(); @@ -4009,9 +4586,9 @@ export function compileCall( } case BuiltinNames.v128_all_true: { // all_true(a: v128) -> bool if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) ) { compiler.currentType = Type.bool; return module.unreachable(); @@ -4048,9 +4625,9 @@ export function compileCall( } case BuiltinNames.v128_qfma: { // qfma(a: v128, b: v128, c: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -4073,9 +4650,9 @@ export function compileCall( } case BuiltinNames.v128_qfms: { // qfms(a: v128, b: v128, c: v128) -> v128 if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) ) { compiler.currentType = Type.v128; return module.unreachable(); @@ -4099,30 +4676,10 @@ export function compileCall( // === Internal runtime ======================================================================= - case BuiltinNames.idof: { - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.u32; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let signatureReference = type.signatureReference; - if (signatureReference) { - return module.i32(signatureReference.id); - } - let classReference = type.classReference; - if (classReference !== null && !classReference.hasDecorator(DecoratorFlags.UNMANAGED)) { - return module.i32(classReference.id); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "idof", type.toString() - ); - return module.unreachable(); - } case BuiltinNames.visit_globals: { if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) // cookie + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) // cookie ) { compiler.currentType = Type.void; return module.unreachable(); @@ -4134,8 +4691,8 @@ export function compileCall( } case BuiltinNames.visit_members: { if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) // ref, cookie + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) // ref, cookie ) { compiler.currentType = Type.void; return module.unreachable(); @@ -4146,166 +4703,6 @@ export function compileCall( compiler.currentType = Type.void; return module.call(BuiltinNames.visit_members, [ arg0, arg1 ], NativeType.None); } - case BuiltinNames.isNaN: { - if ( - checkTypeOptional(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto); - let type = compiler.currentType; - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - // never NaN - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: { - return hasSideEffects(arg0) - ? module.block(null, [ - module.drop(arg0), - module.i32(0) - ], NativeType.I32) - : module.i32(0); - } - // (t = arg0) != t - case TypeKind.F32: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.NeF32, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F32) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f32); - let ret = module.binary(BinaryOp.NeF32, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F32) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F64: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.NeF64, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F64) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f64); - let ret = module.binary(BinaryOp.NeF64, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F64) - ); - flow.freeTempLocal(temp); - return ret; - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "isNaN", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.isFinite: { - if ( - checkTypeOptional(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto); - let type = compiler.currentType; - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - // always finite - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: { - return hasSideEffects(arg0) - ? module.block(null, [ - module.drop(arg0), - module.i32(1) - ], NativeType.I32) - : module.i32(1); - } - // (t = arg0) - t == 0 - case TypeKind.F32: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.EqF32, - module.binary(BinaryOp.SubF32, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F32) - ), - module.f32(0) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f32); - let ret = module.binary(BinaryOp.EqF32, - module.binary(BinaryOp.SubF32, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F32) - ), - module.f32(0) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F64: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.EqF64, - module.binary(BinaryOp.SubF64, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F64) - ), - module.f64(0) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f64); - let ret = module.binary(BinaryOp.EqF64, - module.binary(BinaryOp.SubF64, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F64) - ), - module.f64(0) - ); - flow.freeTempLocal(temp); - return ret; - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "isFinite", type.toString() - ); - return module.unreachable(); - } } // try to defer inline asm to a concrete built-in @@ -4997,17 +5394,15 @@ export function compileClassInstanceOf(compiler: Compiler, prototype: ClassProto // Helpers /** Evaluates the constant type of a type argument *or* expression. */ -function evaluateConstantType( - compiler: Compiler, - typeArguments: Type[] | null, - operands: Expression[], - reportNode: CallExpression -): Type | null { +function evaluateConstantType(ctx: BuiltinContext): Type | null { + var compiler = ctx.compiler; + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; if (operands.length == 0) { // requires type argument if (!typeArguments || typeArguments.length != 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments ? typeArguments.length.toString() : "0" + ctx.reportNode.typeArgumentsRange, "1", typeArguments ? typeArguments.length.toString() : "0" ); return null; } @@ -5018,7 +5413,7 @@ function evaluateConstantType( if (typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString() + ctx.reportNode.typeArgumentsRange, "1", typeArguments.length.toString() ); return null; } @@ -5031,12 +5426,12 @@ function evaluateConstantType( if (typeArguments && typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString() + ctx.reportNode.typeArgumentsRange, "1", typeArguments.length.toString() ); } compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.argumentsRange, "1", operands.length.toString() + ctx.reportNode.argumentsRange, "1", operands.length.toString() ); return null; } @@ -5077,15 +5472,12 @@ function evaluateImmediateOffset(expression: Expression, compiler: Compiler): i3 } /** Checks that the specified feature is enabled. */ -function checkFeatureEnabled( - feature: Feature, - reportNode: Node, - compiler: Compiler -): i32 { +function checkFeatureEnabled(ctx: BuiltinContext, feature: Feature): i32 { + var compiler = ctx.compiler; if (!compiler.options.hasFeature(feature)) { compiler.error( DiagnosticCode.Feature_0_is_not_enabled, - reportNode.range, featureToString(feature) + ctx.reportNode.range, featureToString(feature) ); return 1; } @@ -5093,12 +5485,9 @@ function checkFeatureEnabled( } /** Checks a call with a single required type argument. Returns `1` on error. */ -function checkTypeRequired( - typeArguments: Type[] | null, - reportNode: CallExpression, - compiler: Compiler, - setCurrentTypeOnError: bool = false -): i32 { +function checkTypeRequired(ctx: BuiltinContext, setCurrentTypeOnError: bool = false): i32 { + var compiler = ctx.compiler; + var typeArguments = ctx.typeArguments; if (typeArguments) { let numTypeArguments = typeArguments.length; if (numTypeArguments == 1) return 0; @@ -5106,32 +5495,29 @@ function checkTypeRequired( if (setCurrentTypeOnError) compiler.currentType = typeArguments[0]; compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", numTypeArguments.toString() + ctx.reportNode.typeArgumentsRange, "1", numTypeArguments.toString() ); } else { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.range, "1", "0" + ctx.reportNode.range, "1", "0" ); } return 1; } /** Checks a call with a single optional type argument. Returns `1` on error. */ -function checkTypeOptional( - typeArguments: Type[] | null, - reportNode: CallExpression, - compiler: Compiler, - setCurrentTypeOnError: bool = false -): i32 { +function checkTypeOptional(ctx: BuiltinContext, setCurrentTypeOnError: bool = false): i32 { + var typeArguments = ctx.typeArguments; if (typeArguments) { + let compiler = ctx.compiler; let numTypeArguments = typeArguments.length; if (numTypeArguments == 1) return 0; assert(numTypeArguments); // invalid if 0, must not be set at all instead if (setCurrentTypeOnError) compiler.currentType = typeArguments[0]; compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", numTypeArguments.toString() + ctx.reportNode.typeArgumentsRange, "1", numTypeArguments.toString() ); return 1; } @@ -5139,15 +5525,13 @@ function checkTypeOptional( } /** Checks a call that is not generic. Returns `1` on error. */ -function checkTypeAbsent( - typeArguments: Type[] | null, - reportNode: CallExpression, - prototype: FunctionPrototype -): i32 { +function checkTypeAbsent(ctx: BuiltinContext): i32 { + var typeArguments = ctx.typeArguments; if (typeArguments) { + let prototype = ctx.prototype; prototype.program.error( DiagnosticCode.Type_0_is_not_generic, - reportNode.typeArgumentsRange, prototype.internalName + ctx.reportNode.typeArgumentsRange, prototype.internalName ); return 1; } @@ -5155,16 +5539,12 @@ function checkTypeAbsent( } /** Checks a call that requires a fixed number of arguments. Returns `1` on error. */ -function checkArgsRequired( - operands: Expression[], - expected: i32, - reportNode: CallExpression, - compiler: Compiler -): i32 { +function checkArgsRequired(ctx: BuiltinContext, expected: i32): i32 { + var operands = ctx.operands; if (operands.length != expected) { - compiler.error( + ctx.compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.range, expected.toString(), operands.length.toString() + ctx.reportNode.range, expected.toString(), operands.length.toString() ); return 1; } @@ -5172,24 +5552,19 @@ function checkArgsRequired( } /** Checks a call that requires a variable number of arguments. Returns `1` on error. */ -function checkArgsOptional( - operands: Expression[], - expectedMinimum: i32, - expectedMaximum: i32, - reportNode: CallExpression, - compiler: Compiler -): i32 { +function checkArgsOptional(ctx: BuiltinContext, expectedMinimum: i32, expectedMaximum: i32): i32 { + var operands = ctx.operands; var numOperands = operands.length; if (numOperands < expectedMinimum) { - compiler.error( + ctx.compiler.error( DiagnosticCode.Expected_at_least_0_arguments_but_got_1, - reportNode.range, expectedMinimum.toString(), numOperands.toString() + ctx.reportNode.range, expectedMinimum.toString(), numOperands.toString() ); return 1; } else if (numOperands > expectedMaximum) { - compiler.error( + ctx.compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.range, expectedMaximum.toString(), numOperands.toString() + ctx.reportNode.range, expectedMaximum.toString(), numOperands.toString() ); return 1; } diff --git a/src/compiler.ts b/src/compiler.ts index a82056ace1..2b0dd1cfe5 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -765,7 +765,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.TYPEDEFINITION: case ElementKind.ENUMVALUE: case ElementKind.INDEXSIGNATURE: break; - default: assert(false, ElementKind[element.kind]); + default: assert(false); } if (compileMembers) { let members = element.members; diff --git a/src/glue/binaryen.d.ts b/src/glue/binaryen.d.ts index 284088ef8d..32d72ffef2 100644 --- a/src/glue/binaryen.d.ts +++ b/src/glue/binaryen.d.ts @@ -14,13 +14,13 @@ export declare function __i32_store16(ptr: usize, value: number): void; export declare function __i32_store(ptr: usize, value: number): void; export declare function __f32_store(ptr: usize, value: number): void; export declare function __f64_store(ptr: usize, value: number): void; -export declare function __i32_load8_s(ptr: usize): number; -export declare function __i32_load8_u(ptr: usize): number; -export declare function __i32_load16_s(ptr: usize): number; -export declare function __i32_load16_u(ptr: usize): number; -export declare function __i32_load(ptr: usize): number; -export declare function __f32_load(ptr: usize): number; -export declare function __f64_load(ptr: usize): number; +export declare function __i32_load8_s(ptr: usize): i8; +export declare function __i32_load8_u(ptr: usize): u8; +export declare function __i32_load16_s(ptr: usize): i16; +export declare function __i32_load16_u(ptr: usize): u16; +export declare function __i32_load(ptr: usize): i32; +export declare function __f32_load(ptr: usize): f32; +export declare function __f64_load(ptr: usize): f64; type BinaryenIndex = u32; diff --git a/src/module.ts b/src/module.ts index ef3913885b..7c9c7d6fa0 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1847,7 +1847,7 @@ export function getFunctionVars(func: FunctionRef): NativeType { // TODO: unify this on Binaryen's side? var count = binaryen._BinaryenFunctionGetNumVars(func); var types = new Array(count); - for (let i = 0; i < count; ++i) { + for (let i: Index = 0; i < count; ++i) { types[i] = binaryen._BinaryenFunctionGetVar(func, i); } return createType(types); @@ -2061,10 +2061,10 @@ function allocString(str: string | null): usize { return ptr; } -function readBuffer(ptr: usize, length: usize): Uint8Array { +function readBuffer(ptr: usize, length: i32): Uint8Array { var ret = new Uint8Array(length); - for (let i: usize = 0; i < length; ++i) { - ret[i] = binaryen.__i32_load8_u(ptr + i); + for (let i = 0; i < length; ++i) { + ret[i] = binaryen.__i32_load8_u(ptr + i); } return ret; } diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 85ffc797ce..2f7b4584a0 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -176,164 +176,124 @@ export function tokenFromKeyword(text: string): Token { assert(text.length); switch (text.charCodeAt(0)) { case CharCode.a: { - switch (text) { - case "abstract": return Token.ABSTRACT; - case "as": return Token.AS; - case "async": return Token.ASYNC; - case "await": return Token.AWAIT; - } + if (text == "abstract") return Token.ABSTRACT; + if (text == "as") return Token.AS; + if (text == "async") return Token.ASYNC; + if (text == "await") return Token.AWAIT; break; } case CharCode.b: { - switch (text) { - case "break": return Token.BREAK; - } + if (text == "break") return Token.BREAK; break; } case CharCode.c: { - switch (text) { - case "case": return Token.CASE; - case "catch": return Token.CATCH; - case "class": return Token.CLASS; - case "continue": return Token.CONTINUE; - case "const": return Token.CONST; - case "constructor": return Token.CONSTRUCTOR; - } + if (text == "case") return Token.CASE; + if (text == "catch") return Token.CATCH; + if (text == "class") return Token.CLASS; + if (text == "continue") return Token.CONTINUE; + if (text == "const") return Token.CONST; + if (text == "constructor") return Token.CONSTRUCTOR; break; } case CharCode.d: { - switch (text) { - case "debugger": return Token.DEBUGGER; - case "declare": return Token.DECLARE; - case "default": return Token.DEFAULT; - case "delete": return Token.DELETE; - case "do": return Token.DO; - } + if (text == "debugger") return Token.DEBUGGER; + if (text == "declare") return Token.DECLARE; + if (text == "default") return Token.DEFAULT; + if (text == "delete") return Token.DELETE; + if (text == "do") return Token.DO; break; } case CharCode.e: { - switch (text) { - case "else": return Token.ELSE; - case "enum": return Token.ENUM; - case "export": return Token.EXPORT; - case "extends": return Token.EXTENDS; - } + if (text == "else") return Token.ELSE; + if (text == "enum") return Token.ENUM; + if (text == "export") return Token.EXPORT; + if (text == "extends") return Token.EXTENDS; break; } case CharCode.f: { - switch (text) { - case "false": return Token.FALSE; - case "finally": return Token.FINALLY; - case "for": return Token.FOR; - case "from": return Token.FROM; - case "function": return Token.FUNCTION; - } + if (text == "false") return Token.FALSE; + if (text == "finally") return Token.FINALLY; + if (text == "for") return Token.FOR; + if (text == "from") return Token.FROM; + if (text == "function") return Token.FUNCTION; break; } case CharCode.g: { - switch (text) { - case "get": return Token.GET; - } + if (text == "get") return Token.GET; break; } case CharCode.i: { - switch (text) { - case "if": return Token.IF; - case "implements": return Token.IMPLEMENTS; - case "import": return Token.IMPORT; - case "in": return Token.IN; - case "instanceof": return Token.INSTANCEOF; - case "interface": return Token.INTERFACE; - case "is": return Token.IS; - } + if (text == "if") return Token.IF; + if (text == "implements") return Token.IMPLEMENTS; + if (text == "import") return Token.IMPORT; + if (text == "in") return Token.IN; + if (text == "instanceof") return Token.INSTANCEOF; + if (text == "interface") return Token.INTERFACE; + if (text == "is") return Token.IS; break; } case CharCode.k: { - switch (text) { - case "keyof": return Token.KEYOF; - } + if (text == "keyof") return Token.KEYOF; break; } case CharCode.l: { - switch (text) { - case "let": return Token.LET; - } + if (text == "let") return Token.LET; break; } case CharCode.m: { - switch (text) { - case "module": return Token.MODULE; - } + if (text == "module") return Token.MODULE; break; } case CharCode.n: { - switch (text) { - case "namespace": return Token.NAMESPACE; - case "new": return Token.NEW; - case "null": return Token.NULL; - } + if (text == "namespace") return Token.NAMESPACE; + if (text == "new") return Token.NEW; + if (text == "null") return Token.NULL; break; } case CharCode.o: { - switch (text) { - case "of": return Token.OF; - } + if (text == "of") return Token.OF; break; } case CharCode.p: { - switch (text) { - case "package": return Token.PACKAGE; - case "private": return Token.PRIVATE; - case "protected": return Token.PROTECTED; - case "public": return Token.PUBLIC; - } + if (text == "package") return Token.PACKAGE; + if (text == "private") return Token.PRIVATE; + if (text == "protected") return Token.PROTECTED; + if (text == "public") return Token.PUBLIC; break; } case CharCode.r: { - switch (text) { - case "readonly": return Token.READONLY; - case "return": return Token.RETURN; - } + if (text == "readonly") return Token.READONLY; + if (text == "return") return Token.RETURN; break; } case CharCode.s: { - switch (text) { - case "set": return Token.SET; - case "static": return Token.STATIC; - case "super": return Token.SUPER; - case "switch": return Token.SWITCH; - } + if (text == "set") return Token.SET; + if (text == "static") return Token.STATIC; + if (text == "super") return Token.SUPER; + if (text == "switch") return Token.SWITCH; break; } case CharCode.t: { - switch (text) { - case "this": return Token.THIS; - case "throw": return Token.THROW; - case "true": return Token.TRUE; - case "try": return Token.TRY; - case "type": return Token.TYPE; - case "typeof": return Token.TYPEOF; - } + if (text == "this") return Token.THIS; + if (text == "throw") return Token.THROW; + if (text == "true") return Token.TRUE; + if (text == "try") return Token.TRY; + if (text == "type") return Token.TYPE; + if (text == "typeof") return Token.TYPEOF; break; } case CharCode.v: { - switch (text) { - case "var": return Token.VAR; - case "void": return Token.VOID; - } + if (text == "var") return Token.VAR; + if (text == "void") return Token.VOID; break; } case CharCode.w: { - switch (text) { - case "while": return Token.WHILE; - case "with": return Token.WITH; - } + if (text == "while") return Token.WHILE; + if (text == "with") return Token.WITH; break; } case CharCode.y: { - switch (text) { - case "yield": return Token.YIELD; - } + if (text == "yield") return Token.YIELD; break; } } From d5b01d8dfcdfa7950746358dbd283db65c2ffe47 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 29 Feb 2020 01:57:19 +0100 Subject: [PATCH 08/28] refactor hell part 2, down to 291 --- src/ast.ts | 2 +- src/builtins.ts | 6137 +++++++++++++++++++++++++++------------ src/compiler.ts | 29 +- src/diagnostics.ts | 6 +- src/flow.ts | 4 +- src/program.ts | 49 +- src/resolver.ts | 31 +- src/types.ts | 13 +- src/util/collections.ts | 4 +- std/portable/index.d.ts | 2 +- 10 files changed, 4362 insertions(+), 1915 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index 4062e98a39..9e0bfb67ec 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -2034,7 +2034,7 @@ export function mangleInternalPath(path: string): string { export function isTypeOmitted(type: TypeNode): bool { if (type.kind == NodeKind.NAMEDTYPE) { let name = (type).name; - return !(name.next || name.identifier.text.length); + return !(name.next !== null || name.identifier.text.length > 0); } return false; } diff --git a/src/builtins.ts b/src/builtins.ts index 5ea62b0b44..b60a768f6c 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -569,7 +569,7 @@ export namespace BuiltinNames { } /** Builtin compilation context. */ -class BuiltinContext { +export class BuiltinContext { /** Compiler reference. */ compiler: Compiler; /** Prototype being called. */ @@ -583,7 +583,7 @@ class BuiltinContext { /** Respective call expression. */ reportNode: CallExpression; /** Whether originating from inline assembly. */ - isAsm: bool; + contextIsExact: bool; } /** Registered builtins. */ @@ -637,9 +637,7 @@ function builtin_isSigned(ctx: BuiltinContext): ExpressionRef { var type = evaluateConstantType(ctx); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - return type.is(TypeFlags.SIGNED) - ? module.i32(1) - : module.i32(0); + return module.i32(i32(type.is(TypeFlags.SIGNED))); } builtins.set(BuiltinNames.isSigned, builtin_isSigned); @@ -2007,7 +2005,7 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef { var contextualType = ctx.contextualType; var type = typeArguments![0]; var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - var arg1 = ctx.isAsm + var arg1 = ctx.contextIsExact ? compiler.compileExpression(operands[1], contextualType, Constraints.CONV_IMPLICIT @@ -2137,7 +2135,7 @@ function builtin_atomic_store(ctx: BuiltinContext): ExpressionRef { return module.unreachable(); } var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - var arg1 = ctx.isAsm + var arg1 = ctx.contextIsExact ? compiler.compileExpression( operands[1], contextualType, @@ -2199,7 +2197,7 @@ function builtin_atomic_binary(ctx: BuiltinContext, op: AtomicRMWOp, opName: str compiler.options.usizeType, Constraints.CONV_IMPLICIT ); - var arg1 = ctx.isAsm + var arg1 = ctx.contextIsExact ? compiler.compileExpression(operands[1], contextualType, Constraints.CONV_IMPLICIT @@ -2295,7 +2293,7 @@ function builtin_atomic_cmpxchg(ctx: BuiltinContext): ExpressionRef { compiler.options.usizeType, Constraints.CONV_IMPLICIT ); - var arg1 = ctx.isAsm + var arg1 = ctx.contextIsExact ? compiler.compileExpression(operands[1], contextualType, Constraints.CONV_IMPLICIT @@ -2545,7 +2543,7 @@ function builtin_changetype(ctx: BuiltinContext): ExpressionRef { checkArgsRequired(ctx, 1) ) return module.unreachable(); var operands = ctx.operands; - var typeArguments = assert(ctx.typeArguments); + var typeArguments = ctx.typeArguments!; var toType = typeArguments[0]; var arg0 = compiler.compileExpression(operands[0], Type.auto); var fromType = compiler.currentType; @@ -2782,7 +2780,7 @@ function builtin_instantiate(ctx: BuiltinContext): ExpressionRef { checkTypeRequired(ctx, true) ) return module.unreachable(); var operands = ctx.operands; - var typeArguments = assert(ctx.typeArguments); + var typeArguments = ctx.typeArguments!; var typeArgument = typeArguments[0]; var classInstance = typeArgument.classReference; if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) { @@ -3149,1938 +3147,4373 @@ function builtin_f64x2(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2, builtin_f64x2); -/** Compiles a call to a built-in function. */ -export function compileCall( - /* Compiler reference. */ - compiler: Compiler, - /** Respective function prototype. */ - prototype: FunctionPrototype, - /** Pre-resolved type arguments. */ - typeArguments: Type[] | null, - /** Operand expressions. */ - operands: Expression[], - /** Contextual type. */ - contextualType: Type, - /** Respective call expression. */ - reportNode: CallExpression, - /** Indicates that contextual type is ASM type. */ - isAsm: bool = false -): ExpressionRef { - - // TODO: call this from the compiler and cache ctx - var ctx = new BuiltinContext(); - ctx.compiler = compiler; - ctx.prototype = prototype; - ctx.typeArguments = typeArguments; - ctx.operands = operands; - ctx.contextualType = contextualType; - ctx.reportNode = reportNode; - ctx.isAsm = isAsm; - - // Handle registered builtin - var internalName = prototype.internalName; - if (builtins.has(internalName)) { - let fn = builtins.get(internalName)!; - return fn(ctx); - } - - // Fall back to legacy builtins (TODO: port 'em all) +// v128.splat(x: T) -> v128 +function builtin_v128_splat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; var module = compiler.module; - - switch (prototype.internalName) { - - // === SIMD =================================================================================== - - case BuiltinNames.v128_splat: { // splat(x: T) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], type, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.SplatI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.SplatI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.SplatI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.SplatI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.SplatI64x2 - : UnaryOp.SplatI32x4, - arg0 - ); - } - case TypeKind.F32: return module.unary(UnaryOp.SplatF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SplatF64x2, arg0); - } + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], type, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.SplatI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.SplatI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.SplatI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.SplatI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.SplatI64x2 + : UnaryOp.SplatI32x4, + arg0 + ); } + case TypeKind.F32: return module.unary(UnaryOp.SplatF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.SplatF64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.splat", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_splat, builtin_v128_splat); + +// v128.extract_lane(x: v128, idx: u8) -> T +function builtin_v128_extract_lane(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); + compiler.currentType = type; + var idx = 0; + if (getExpressionId(arg1) == ExpressionId.Const) { + assert(getExpressionType(arg1) == NativeType.I32); + idx = getConstValueI32(arg1); + } else { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operands[1].range + ); + } + if (!type.is(TypeFlags.REFERENCE)) { + let maxIdx = (16 / assert(type.byteSize)) - 1; + if (idx < 0 || idx > maxIdx) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.splat", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[1].range, "Lane index", "0", maxIdx.toString() ); - return module.unreachable(); + idx = 0; } - case BuiltinNames.v128_extract_lane: { // extract_lane(x: v128, idx: u8) -> T - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx, true) | - checkArgsRequired(ctx, 2) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); - compiler.currentType = type; - let idx = 0; - if (getExpressionId(arg1) == ExpressionId.Const) { - assert(getExpressionType(arg1) == NativeType.I32); - idx = getConstValueI32(arg1); - } else { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - operands[1].range + switch (type.kind) { + case TypeKind.I8: return module.simd_extract(SIMDExtractOp.ExtractLaneI8x16, arg0, idx); + case TypeKind.U8: return module.simd_extract(SIMDExtractOp.ExtractLaneU8x16, arg0, idx); + case TypeKind.I16: return module.simd_extract(SIMDExtractOp.ExtractLaneI16x8, arg0, idx); + case TypeKind.U16: return module.simd_extract(SIMDExtractOp.ExtractLaneU16x8, arg0, idx); + case TypeKind.I32: + case TypeKind.U32: return module.simd_extract(SIMDExtractOp.ExtractLaneI32x4, arg0, idx); + case TypeKind.I64: + case TypeKind.U64: return module.simd_extract(SIMDExtractOp.ExtractLaneI64x2, arg0, idx); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.simd_extract( + compiler.options.isWasm64 + ? SIMDExtractOp.ExtractLaneI64x2 + : SIMDExtractOp.ExtractLaneI32x4, + arg0, idx ); } - if (!type.is(TypeFlags.REFERENCE)) { - let maxIdx = (16 / assert(type.byteSize)) - 1; - if (idx < 0 || idx > maxIdx) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[1].range, "Lane index", "0", maxIdx.toString() - ); - idx = 0; - } - switch (type.kind) { - case TypeKind.I8: return module.simd_extract(SIMDExtractOp.ExtractLaneI8x16, arg0, idx); - case TypeKind.U8: return module.simd_extract(SIMDExtractOp.ExtractLaneU8x16, arg0, idx); - case TypeKind.I16: return module.simd_extract(SIMDExtractOp.ExtractLaneI16x8, arg0, idx); - case TypeKind.U16: return module.simd_extract(SIMDExtractOp.ExtractLaneU16x8, arg0, idx); - case TypeKind.I32: - case TypeKind.U32: return module.simd_extract(SIMDExtractOp.ExtractLaneI32x4, arg0, idx); - case TypeKind.I64: - case TypeKind.U64: return module.simd_extract(SIMDExtractOp.ExtractLaneI64x2, arg0, idx); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.simd_extract( - compiler.options.isWasm64 - ? SIMDExtractOp.ExtractLaneI64x2 - : SIMDExtractOp.ExtractLaneI32x4, - arg0, idx - ); - } - case TypeKind.F32: return module.simd_extract(SIMDExtractOp.ExtractLaneF32x4, arg0, idx); - case TypeKind.F64: return module.simd_extract(SIMDExtractOp.ExtractLaneF64x2, arg0, idx); - } - } + case TypeKind.F32: return module.simd_extract(SIMDExtractOp.ExtractLaneF32x4, arg0, idx); + case TypeKind.F64: return module.simd_extract(SIMDExtractOp.ExtractLaneF64x2, arg0, idx); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.extract_lane", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_extract_lane, builtin_v128_extract_lane); + +// v128.replace_lane(x: v128, idx: u8, value: T) -> v128 +function builtin_v128_replace_lane(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], type, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + var idx = 0; + if (getExpressionId(arg1) == ExpressionId.Const) { + assert(getExpressionType(arg1) == NativeType.I32); + idx = getConstValueI32(arg1); + } else { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operands[1].range + ); + } + if (!type.is(TypeFlags.REFERENCE)) { + let maxIdx = (16 / assert(type.byteSize)) - 1; + if (idx < 0 || idx > maxIdx) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.extract_lane", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[1].range, "Lane index", "0", maxIdx.toString() ); - return module.unreachable(); + idx = 0; } - case BuiltinNames.v128_replace_lane: { // replace_lane(x: v128, idx: u8, value: T) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 3) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], type, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - let idx = 0; - if (getExpressionId(arg1) == ExpressionId.Const) { - assert(getExpressionType(arg1) == NativeType.I32); - idx = getConstValueI32(arg1); - } else { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - operands[1].range + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI8x16, arg0, idx, arg2); + case TypeKind.I16: + case TypeKind.U16: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI16x8, arg0, idx, arg2); + case TypeKind.I32: + case TypeKind.U32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI32x4, arg0, idx, arg2); + case TypeKind.I64: + case TypeKind.U64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI64x2, arg0, idx, arg2); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.simd_replace( + compiler.options.isWasm64 + ? SIMDReplaceOp.ReplaceLaneI64x2 + : SIMDReplaceOp.ReplaceLaneI32x4, + arg0, idx, arg2 ); } - if (!type.is(TypeFlags.REFERENCE)) { - let maxIdx = (16 / assert(type.byteSize)) - 1; - if (idx < 0 || idx > maxIdx) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[1].range, "Lane index", "0", maxIdx.toString() - ); - idx = 0; - } - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI8x16, arg0, idx, arg2); - case TypeKind.I16: - case TypeKind.U16: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI16x8, arg0, idx, arg2); - case TypeKind.I32: - case TypeKind.U32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI32x4, arg0, idx, arg2); - case TypeKind.I64: - case TypeKind.U64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI64x2, arg0, idx, arg2); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.simd_replace( - compiler.options.isWasm64 - ? SIMDReplaceOp.ReplaceLaneI64x2 - : SIMDReplaceOp.ReplaceLaneI32x4, - arg0, idx, arg2 + case TypeKind.F32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF32x4, arg0, idx, arg2); + case TypeKind.F64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF64x2, arg0, idx, arg2); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.replace_lane", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_replace_lane, builtin_v128_replace_lane); + +// v128.shuffle(a: v128, b: v128, ...lanes: u8[]) -> v128 +function builtin_v128_shuffle(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + if (!type.is(TypeFlags.REFERENCE)) { + let laneWidth = type.byteSize; + let laneCount = 16 / laneWidth; + assert(isInteger(laneCount) && isPowerOf2(laneCount)); + if ( + checkArgsRequired(ctx, 2 + laneCount) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.F32: + case TypeKind.F64: { + let mask = new Uint8Array(16); + let maxIdx = (laneCount << 1) - 1; + for (let i = 0; i < laneCount; ++i) { + let operand = operands[2 + i]; + let argN = compiler.precomputeExpression(operand, Type.u8, Constraints.CONV_IMPLICIT); + if (getExpressionId(argN) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operand.range + ); + compiler.currentType = Type.v128; + return module.unreachable(); + } + assert(getExpressionType(argN) == NativeType.I32); + let idx = getConstValueI32(argN); + if (idx < 0 || idx > maxIdx) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operand.range, "Lane index", "0", maxIdx.toString() ); + compiler.currentType = Type.v128; + return module.unreachable(); + } + switch (laneWidth) { + case 1: { + writeI8(idx, mask, i); + break; + } + case 2: { + let off8 = i << 1; + let idx8 = idx << 1; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + break; + } + case 4: { + let off8 = i << 2; + let idx8 = idx << 2; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + writeI8(idx8 + 2, mask, off8 + 2); + writeI8(idx8 + 3, mask, off8 + 3); + break; + } + case 8: { + let off8 = i << 3; + let idx8 = idx << 3; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + writeI8(idx8 + 2, mask, off8 + 2); + writeI8(idx8 + 3, mask, off8 + 3); + writeI8(idx8 + 4, mask, off8 + 4); + writeI8(idx8 + 5, mask, off8 + 5); + writeI8(idx8 + 6, mask, off8 + 6); + writeI8(idx8 + 7, mask, off8 + 7); + break; + } + default: assert(false); } - case TypeKind.F32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF32x4, arg0, idx, arg2); - case TypeKind.F64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF64x2, arg0, idx, arg2); } + compiler.currentType = Type.v128; + return module.simd_shuffle(arg0, arg1, mask); } + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.shuffle", type.toString() + ); + compiler.currentType = Type.v128; + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_shuffle, builtin_v128_shuffle); + +// v128.swizzle(a: v128, b: v128) -> v128 +function builtin_v128_swizzle(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + return module.binary(BinaryOp.SwizzleV8x16, arg0, arg1); +} +builtins.set(BuiltinNames.v128_swizzle, builtin_v128_swizzle); + +// v128.load_splat(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 +function builtin_v128_load_splat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var numOperands = operands.length; + var immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (numOperands == 3) { + immAlign = evaluateImmediateOffset(operands[2], compiler); + if (immAlign < 0) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + } else { + immAlign = naturalAlign; + } + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + if (immAlign > naturalAlign) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.replace_lane", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() ); return module.unreachable(); } - case BuiltinNames.v128_shuffle: { // shuffle(a: v128, b: v128, ...lanes: u8[]) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - if (!type.is(TypeFlags.REFERENCE)) { - let laneWidth = type.byteSize; - let laneCount = 16 / laneWidth; - assert(isInteger(laneCount) && isPowerOf2(laneCount)); - if ( - checkArgsRequired(ctx, 2 + laneCount) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.F32: - case TypeKind.F64: { - let mask = new Uint8Array(16); - let maxIdx = (laneCount << 1) - 1; - for (let i = 0; i < laneCount; ++i) { - let operand = operands[2 + i]; - let argN = compiler.precomputeExpression(operand, Type.u8, Constraints.CONV_IMPLICIT); - if (getExpressionId(argN) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - operand.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(argN) == NativeType.I32); - let idx = getConstValueI32(argN); - if (idx < 0 || idx > maxIdx) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operand.range, "Lane index", "0", maxIdx.toString() - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - switch (laneWidth) { - case 1: { - writeI8(idx, mask, i); - break; - } - case 2: { - let off8 = i << 1; - let idx8 = idx << 1; - writeI8(idx8 , mask, off8); - writeI8(idx8 + 1, mask, off8 + 1); - break; - } - case 4: { - let off8 = i << 2; - let idx8 = idx << 2; - writeI8(idx8 , mask, off8); - writeI8(idx8 + 1, mask, off8 + 1); - writeI8(idx8 + 2, mask, off8 + 2); - writeI8(idx8 + 3, mask, off8 + 3); - break; - } - case 8: { - let off8 = i << 3; - let idx8 = idx << 3; - writeI8(idx8 , mask, off8); - writeI8(idx8 + 1, mask, off8 + 1); - writeI8(idx8 + 2, mask, off8 + 2); - writeI8(idx8 + 3, mask, off8 + 3); - writeI8(idx8 + 4, mask, off8 + 4); - writeI8(idx8 + 5, mask, off8 + 5); - writeI8(idx8 + 6, mask, off8 + 6); - writeI8(idx8 + 7, mask, off8 + 7); - break; - } - default: assert(false); - } - } - compiler.currentType = Type.v128; - return module.simd_shuffle(arg0, arg1, mask); - } - } - } + if (!isPowerOf2(immAlign)) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.shuffle", type.toString() + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" ); - compiler.currentType = Type.v128; return module.unreachable(); } - case BuiltinNames.v128_swizzle: { // swizzle(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { + return module.simd_load(SIMDLoadOp.LoadSplatV8x16, arg0, immOffset, immAlign); } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.SwizzleV8x16, arg0, arg1); - } - case BuiltinNames.v128_load_splat: { // load_splat(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx, true) | - checkArgsOptional(ctx, 1, 3) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let numOperands = operands.length; - let immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); + case TypeKind.I16: + case TypeKind.U16: { + return module.simd_load(SIMDLoadOp.LoadSplatV16x8, arg0, immOffset, immAlign); } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (numOperands == 3) { - immAlign = evaluateImmediateOffset(operands[2], compiler); - if (immAlign < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; + case TypeKind.I32: + case TypeKind.U32: + case TypeKind.F32: { + return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); } - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[2].range, "Alignment", "0", naturalAlign.toString() - ); - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[2].range, "Alignment" - ); - return module.unreachable(); - } - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: { - return module.simd_load(SIMDLoadOp.LoadSplatV8x16, arg0, immOffset, immAlign); - } - case TypeKind.I16: - case TypeKind.U16: { - return module.simd_load(SIMDLoadOp.LoadSplatV16x8, arg0, immOffset, immAlign); - } - case TypeKind.I32: - case TypeKind.U32: - case TypeKind.F32: { - return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); - } - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); - } - // fall-through - } - case TypeKind.I64: - case TypeKind.U64: - case TypeKind.F64: { - return module.simd_load(SIMDLoadOp.LoadSplatV64x2, arg0, immOffset, immAlign); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.load_splat", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_load_ext: { // load_ext(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx, true) | - checkArgsOptional(ctx, 1, 3) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let numOperands = operands.length; - let immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (numOperands == 3) { - immAlign = evaluateImmediateOffset(operands[2], compiler); - if (immAlign < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); } - } else { - immAlign = naturalAlign; + // fall-through } - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[2].range, "Alignment", "0", naturalAlign.toString() - ); - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[2].range, "Alignment" - ); - return module.unreachable(); - } - switch (type.kind) { - case TypeKind.I8: return module.simd_load(SIMDLoadOp.LoadI8ToI16x8, arg0, immOffset, immAlign); - case TypeKind.U8: return module.simd_load(SIMDLoadOp.LoadU8ToU16x8, arg0, immOffset, immAlign); - case TypeKind.I16: return module.simd_load(SIMDLoadOp.LoadI16ToI32x4, arg0, immOffset, immAlign); - case TypeKind.U16: return module.simd_load(SIMDLoadOp.LoadU16ToU32x4, arg0, immOffset, immAlign); - case TypeKind.ISIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.I32: return module.simd_load(SIMDLoadOp.LoadI32ToI64x2, arg0, immOffset, immAlign); - case TypeKind.USIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.U32: return module.simd_load(SIMDLoadOp.LoadU32ToU64x2, arg0, immOffset, immAlign); - } + case TypeKind.I64: + case TypeKind.U64: + case TypeKind.F64: { + return module.simd_load(SIMDLoadOp.LoadSplatV64x2, arg0, immOffset, immAlign); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.load_ext", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.v128_add: { // add(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.AddI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.AddI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.AddI32x4, arg0, arg1); - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.AddI64x2, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.AddI64x2 - : BinaryOp.AddI32x4, - arg0, arg1 - ); - } - case TypeKind.F32: return module.binary(BinaryOp.AddF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.AddF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.add", type.toString() - ); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.load_splat", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_load_splat, builtin_v128_load_splat); + +// v128.load_ext(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 +function builtin_v128_load_ext(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var numOperands = operands.length; + var immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (numOperands == 3) { + immAlign = evaluateImmediateOffset(operands[2], compiler); + if (immAlign < 0) { + compiler.currentType = Type.v128; return module.unreachable(); } - case BuiltinNames.v128_sub: { // sub(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.SubI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.SubI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.SubI32x4, arg0, arg1); - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.SubI64x2, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.SubI64x2 - : BinaryOp.SubI32x4, - arg0, arg1 - ); - } - case TypeKind.F32: return module.binary(BinaryOp.SubF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.SubF64x2, arg0, arg1); - } - } + } else { + immAlign = naturalAlign; + } + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + if (immAlign > naturalAlign) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.sub", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() ); return module.unreachable(); } - case BuiltinNames.v128_mul: { // mul(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.MulI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.MulI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.MulI32x4, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.MulI32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.MulF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MulF64x2, arg0, arg1); - } - } + if (!isPowerOf2(immAlign)) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.mul", type.toString() + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" ); return module.unreachable(); } - case BuiltinNames.v128_div: { // div(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + switch (type.kind) { + case TypeKind.I8: return module.simd_load(SIMDLoadOp.LoadI8ToI16x8, arg0, immOffset, immAlign); + case TypeKind.U8: return module.simd_load(SIMDLoadOp.LoadU8ToU16x8, arg0, immOffset, immAlign); + case TypeKind.I16: return module.simd_load(SIMDLoadOp.LoadI16ToI32x4, arg0, immOffset, immAlign); + case TypeKind.U16: return module.simd_load(SIMDLoadOp.LoadU16ToU32x4, arg0, immOffset, immAlign); + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.binary(BinaryOp.DivF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.DivF64x2, arg0, arg1); - } + case TypeKind.I32: return module.simd_load(SIMDLoadOp.LoadI32ToI64x2, arg0, immOffset, immAlign); + case TypeKind.USIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.div", type.toString() - ); - return module.unreachable(); + case TypeKind.U32: return module.simd_load(SIMDLoadOp.LoadU32ToU64x2, arg0, immOffset, immAlign); } - case BuiltinNames.v128_add_saturate: { // add_saturate(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.AddSatI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.AddSatU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.AddSatI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.AddSatU16x8, arg0, arg1); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.load_ext", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_load_ext, builtin_v128_load_ext); + +// v128.add(a: v128, b: v128) -> v128 +function builtin_v128_add(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.AddI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.AddI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.AddI32x4, arg0, arg1); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.AddI64x2, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.AddI64x2 + : BinaryOp.AddI32x4, + arg0, arg1 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.add_saturate", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.AddF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.AddF64x2, arg0, arg1); } - case BuiltinNames.v128_sub_saturate: { // sub_saturate(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.SubSatI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.SubSatU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.SubSatI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.SubSatU16x8, arg0, arg1); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.add", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_add, builtin_v128_add); + +// v128.sub(a: v128, b: v128) -> v128 +function builtin_v128_sub(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.SubI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.SubI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.SubI32x4, arg0, arg1); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.SubI64x2, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.SubI64x2 + : BinaryOp.SubI32x4, + arg0, arg1 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.sub_saturate", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.SubF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.SubF64x2, arg0, arg1); } - case BuiltinNames.v128_min: { // min(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.MinI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.MinU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.MinI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.MinU16x8, arg0, arg1); - case TypeKind.ISIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.I32: return module.binary(BinaryOp.MinI32x4, arg0, arg1); - case TypeKind.USIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.U32: return module.binary(BinaryOp.MinU32x4, arg0, arg1); - case TypeKind.F32: return module.binary(BinaryOp.MinF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MinF64x2, arg0, arg1); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.sub", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_sub, builtin_v128_sub); + +// v128.mul(a: v128, b: v128) -> v128 +function builtin_v128_mul(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.MulI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.MulI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.MulI32x4, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.MulI32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.min", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.MulF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MulF64x2, arg0, arg1); } - case BuiltinNames.v128_max: { // max(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.MaxI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.MaxU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.MaxI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.MaxU16x8, arg0, arg1); - case TypeKind.ISIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.I32: return module.binary(BinaryOp.MaxI32x4, arg0, arg1); - case TypeKind.USIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.U32: return module.binary(BinaryOp.MaxU32x4, arg0, arg1); - case TypeKind.F32: return module.binary(BinaryOp.MaxF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MaxF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.max", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.mul", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_mul, builtin_v128_mul); + +// v128.div(a: v128, b: v128) -> v128 +function builtin_v128_div(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.binary(BinaryOp.DivF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.DivF64x2, arg0, arg1); } - case BuiltinNames.v128_dot: { // dot(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I16: return module.binary(BinaryOp.DotI16x8, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.dot", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.div", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_div, builtin_v128_div); + +// v128.add_saturate(a: v128, b: v128) -> v128 +function builtin_v128_add_saturate(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.AddSatI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.AddSatU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.AddSatI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.AddSatU16x8, arg0, arg1); } - case BuiltinNames.v128_avgr: { // avgr(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.U8: return module.binary(BinaryOp.AvgrU8x16, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.AvgrU16x8, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.avgr", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.add_saturate", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_add_saturate, builtin_v128_add_saturate); + +// v128.sub_saturate(a: v128, b: v128) -> v128 +function builtin_v128_sub_saturate(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.SubSatI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.SubSatU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.SubSatI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.SubSatU16x8, arg0, arg1); } - case BuiltinNames.v128_eq: { // eq(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.sub_saturate", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_sub_saturate, builtin_v128_sub_saturate); + +// v128.min(a: v128, b: v128) -> v128 +function builtin_v128_min(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.MinI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.MinU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.MinI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.MinU16x8, arg0, arg1); + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.EqI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.EqI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.EqI32x4, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.EqI32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.EqF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.EqF64x2, arg0, arg1); - } + case TypeKind.I32: return module.binary(BinaryOp.MinI32x4, arg0, arg1); + case TypeKind.USIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.eq", type.toString() - ); - return module.unreachable(); + case TypeKind.U32: return module.binary(BinaryOp.MinU32x4, arg0, arg1); + case TypeKind.F32: return module.binary(BinaryOp.MinF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MinF64x2, arg0, arg1); } - case BuiltinNames.v128_ne: { // ne(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.min", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_min, builtin_v128_min); + +// v128.max(a: v128, b: v128) -> v128 +function builtin_v128_max(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.MaxI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.MaxU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.MaxI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.MaxU16x8, arg0, arg1); + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.NeI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.NeI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.NeI32x4, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.NeI32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.NeF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.NeF64x2, arg0, arg1); - } + case TypeKind.I32: return module.binary(BinaryOp.MaxI32x4, arg0, arg1); + case TypeKind.USIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.ne", type.toString() - ); - return module.unreachable(); + case TypeKind.U32: return module.binary(BinaryOp.MaxU32x4, arg0, arg1); + case TypeKind.F32: return module.binary(BinaryOp.MaxF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MaxF64x2, arg0, arg1); } - case BuiltinNames.v128_lt: { // lt(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.LtI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.LtU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.LtI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.LtU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.LtI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.LtU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LtI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LtU32x4, arg0, arg1); - } - break; + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.max", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_max, builtin_v128_max); + +// v128.dot(a: v128, b: v128) -> v128 +function builtin_v128_dot(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I16: return module.binary(BinaryOp.DotI16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.dot", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_dot, builtin_v128_dot); + +// v128.avgr(a: v128, b: v128) -> v128 +function builtin_v128_avgr(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.U8: return module.binary(BinaryOp.AvgrU8x16, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.AvgrU16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.avgr", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_avgr, builtin_v128_avgr); + +// v128.eq(a: v128, b: v128) -> v128 +function builtin_v128_eq(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.EqI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.EqI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.EqI32x4, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.EqI32x4, arg0, arg1); } - case TypeKind.F32: return module.binary(BinaryOp.LtF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.LtF64x2, arg0, arg1); + break; } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.lt", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.EqF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.EqF64x2, arg0, arg1); } - case BuiltinNames.v128_le: { // le(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.LeI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.LeU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.LeI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.LeU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.LeI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.LeU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LeI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LeU32x4, arg0, arg1); - } - break; + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.eq", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_eq, builtin_v128_eq); + +// v128.ne(a: v128, b: v128) -> v128 +function builtin_v128_ne(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.NeI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.NeI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.NeI32x4, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.NeI32x4, arg0, arg1); } - case TypeKind.F32: return module.binary(BinaryOp.LeF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.LeF64x2, arg0, arg1); + break; } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.le", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.NeF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.NeF64x2, arg0, arg1); } - case BuiltinNames.v128_gt: { // gt(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.ne", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_ne, builtin_v128_ne); + +// v128.lt(a: v128, b: v128) -> v128 +function builtin_v128_lt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.LtI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.LtU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.LtI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.LtU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.LtI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.LtU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LtI32x4, arg0, arg1); + } + break; } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.GtI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.GtU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.GtI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.GtU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.GtI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.GtU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GtI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GtU32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.GtF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.GtF64x2, arg0, arg1); + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LtU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.gt", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.LtF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.LtF64x2, arg0, arg1); } - case BuiltinNames.v128_ge: { // ge(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.GeI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.GeU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.GeI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.GeU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.GeI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.GeU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GeI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GeU32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.GeF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.GeF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.ge", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_narrow: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I16: return module.binary(BinaryOp.NarrowI16x8ToI8x16, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.NarrowU16x8ToU8x16, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.NarrowI32x4ToI16x8, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.NarrowU32x4ToU16x8, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.narrow", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_neg: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.NegI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.NegI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.NegI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.NegI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.NegI64x2 - : UnaryOp.NegI32x4, - arg0 - ); - } - case TypeKind.F32: return module.unary(UnaryOp.NegF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.NegF64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.neg", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_abs: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.unary(UnaryOp.AbsF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.AbsF64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.abs", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_sqrt: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.unary(UnaryOp.SqrtF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SqrtF64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.sqrt", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_convert: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I32: return module.unary(UnaryOp.ConvertI32x4ToF32x4, arg0); - case TypeKind.U32: return module.unary(UnaryOp.ConvertU32x4ToF32x4, arg0); - case TypeKind.I64: return module.unary(UnaryOp.ConvertI64x2ToF64x2, arg0); - case TypeKind.U64: return module.unary(UnaryOp.ConvertU64x2ToF64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.convert", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_trunc_sat: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I32: return module.unary(UnaryOp.TruncSatF32x4ToI32x4, arg0); - case TypeKind.U32: return module.unary(UnaryOp.TruncSatF32x4ToU32x4, arg0); - case TypeKind.I64: return module.unary(UnaryOp.TruncSatF64x2ToI64x2, arg0); - case TypeKind.U64: return module.unary(UnaryOp.TruncSatF64x2ToU64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.trunc_sat", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_widen_low: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.unary(UnaryOp.WidenLowI8x16ToI16x8, arg0); - case TypeKind.U8: return module.unary(UnaryOp.WidenLowU8x16ToU16x8, arg0); - case TypeKind.I16: return module.unary(UnaryOp.WidenLowI16x8ToI32x4, arg0); - case TypeKind.U16: return module.unary(UnaryOp.WidenLowU16x8ToU32x4, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.widen_low", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_widen_high: { - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.unary(UnaryOp.WidenHighI8x16ToI16x8, arg0); - case TypeKind.U8: return module.unary(UnaryOp.WidenHighU8x16ToU16x8, arg0); - case TypeKind.I16: return module.unary(UnaryOp.WidenHighI16x8ToI32x4, arg0); - case TypeKind.U16: return module.unary(UnaryOp.WidenHighU16x8ToU32x4, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.widen_high", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_shl: { // shl(a: v128, b: i32) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShlI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShlI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShlI32x4, arg0, arg1); - case TypeKind.I64: - case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShlI64x2, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.simd_shift( - compiler.options.isWasm64 - ? SIMDShiftOp.ShlI64x2 - : SIMDShiftOp.ShlI32x4, - arg0, arg1 - ); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.lt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_lt, builtin_v128_lt); + +// v128.le(a: v128, b: v128) -> v128 +function builtin_v128_le(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.LeI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.LeU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.LeI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.LeU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.LeI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.LeU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LeI32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.shl", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_shr: { // shr(a: v128, b: i32) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.simd_shift(SIMDShiftOp.ShrI8x16, arg0, arg1); - case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShrU8x16, arg0, arg1); - case TypeKind.I16: return module.simd_shift(SIMDShiftOp.ShrI16x8, arg0, arg1); - case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShrU16x8, arg0, arg1); - case TypeKind.I32: return module.simd_shift(SIMDShiftOp.ShrI32x4, arg0, arg1); - case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShrU32x4, arg0, arg1); - case TypeKind.I64: return module.simd_shift(SIMDShiftOp.ShrI64x2, arg0, arg1); - case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShrU64x2, arg0, arg1); - case TypeKind.ISIZE: { - return module.simd_shift( - compiler.options.isWasm64 - ? SIMDShiftOp.ShrI64x2 - : SIMDShiftOp.ShrI32x4, - arg0, arg1 - ); - } - case TypeKind.USIZE: { - return module.simd_shift( - compiler.options.isWasm64 - ? SIMDShiftOp.ShrU64x2 - : SIMDShiftOp.ShrU32x4, - arg0, arg1 - ); - } + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LeU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.shr", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_and: { // and(a: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.AndV128, arg0, arg1); - } - case BuiltinNames.v128_or: { // or(a: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.OrV128, arg0, arg1); - } - case BuiltinNames.v128_xor: { // xor(a: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.XorV128, arg0, arg1); - } - case BuiltinNames.v128_andnot: { // andnot(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 2) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.AndNotV128, arg0, arg1); - } - case BuiltinNames.v128_not: { // not(a: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - return module.unary(UnaryOp.NotV128, arg0); - } - case BuiltinNames.v128_bitselect: { // bitselect(v1: v128, v2: v128, c: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 3) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); - return module.simd_ternary(SIMDTernaryOp.Bitselect, arg0, arg1, arg2); + case TypeKind.F32: return module.binary(BinaryOp.LeF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.LeF64x2, arg0, arg1); } - case BuiltinNames.v128_any_true: { // any_true(a: v128) -> bool - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.AnyTrueI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.AnyTrueI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.AnyTrueI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.AnyTrueI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.AnyTrueI64x2 - : UnaryOp.AnyTrueI32x4, - arg0 - ); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.le", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_le, builtin_v128_le); + +// v128.gt(a: v128, b: v128) -> v128 +function builtin_v128_gt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.GtI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.GtU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.GtI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.GtU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.GtI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.GtU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GtI32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.any_true", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_all_true: { // all_true(a: v128) -> bool - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 1) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.AllTrueI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.AllTrueI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.AllTrueI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.AllTrueI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.AllTrueI64x2 - : UnaryOp.AllTrueI32x4, - arg0 - ); - } + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GtU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.all_true", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.GtF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.GtF64x2, arg0, arg1); } - case BuiltinNames.v128_qfma: { // qfma(a: v128, b: v128, c: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 3) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMAF32x4, arg0, arg1, arg2); - case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMAF64x2, arg0, arg1, arg2); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.gt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_gt, builtin_v128_gt); + +// v128.ge(a: v128, b: v128) -> v128 +function builtin_v128_ge(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.GeI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.GeU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.GeI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.GeU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.GeI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.GeU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GeI32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.qfma", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_qfms: { // qfms(a: v128, b: v128, c: v128) -> v128 - if ( - checkFeatureEnabled(ctx, Feature.SIMD) | - checkTypeRequired(ctx) | - checkArgsRequired(ctx, 3) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMSF32x4, arg0, arg1, arg2); - case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMSF64x2, arg0, arg1, arg2); + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GeU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.qfms", type.toString() - ); - return module.unreachable(); - } - - // === Internal runtime ======================================================================= - - case BuiltinNames.visit_globals: { - if ( - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 1) // cookie - ) { - compiler.currentType = Type.void; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.u32, Constraints.CONV_IMPLICIT); - compiler.runtimeFeatures |= RuntimeFeatures.visitGlobals; - compiler.currentType = Type.void; - return module.call(BuiltinNames.visit_globals, [ arg0 ], NativeType.None); - } - case BuiltinNames.visit_members: { - if ( - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 2) // ref, cookie - ) { - compiler.currentType = Type.void; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.u32, Constraints.CONV_IMPLICIT); - compiler.runtimeFeatures |= RuntimeFeatures.visitMembers; - compiler.currentType = Type.void; - return module.call(BuiltinNames.visit_members, [ arg0, arg1 ], NativeType.None); - } - } - - // try to defer inline asm to a concrete built-in - { - let expr = tryDeferASM(compiler, prototype, operands, reportNode); - if (expr) { - if (typeArguments) { - compiler.error( - DiagnosticCode.Type_0_is_not_generic, - reportNode.typeArgumentsRange, prototype.internalName - ); - } - return expr; + case TypeKind.F32: return module.binary(BinaryOp.GeF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.GeF64x2, arg0, arg1); } } compiler.error( - DiagnosticCode.Not_implemented, - reportNode.expression.range + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.ge", type.toString() ); return module.unreachable(); } +builtins.set(BuiltinNames.v128_ge, builtin_v128_ge); -/** Tries to defer an inline-assembler-like call to a built-in function. */ -function tryDeferASM( - compiler: Compiler, - prototype: FunctionPrototype, - operands: Expression[], - reportNode: CallExpression -): ExpressionRef { - /* tslint:disable:max-line-length */ - switch (prototype.internalName) { - - // TODO: Operators can't be just deferred (don't have a corresponding generic built-in) - // add, sub, mul, div_s, div_u, rem_s, rem_u - // and, or, xor, shl, shr_u, shr_s - // eq, eqz, ne, lt_s, lt_u, le_s, le_u, gt_s, gt_u, ge_s, ge_u - - case BuiltinNames.i32_clz: return deferASM(BuiltinNames.clz, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_clz: return deferASM(BuiltinNames.clz, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_ctz: return deferASM(BuiltinNames.ctz, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_ctz: return deferASM(BuiltinNames.ctz, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_popcnt: return deferASM(BuiltinNames.popcnt, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_popcnt: return deferASM(BuiltinNames.popcnt, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_rotl: return deferASM(BuiltinNames.rotl, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_rotl: return deferASM(BuiltinNames.rotl, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_rotr: return deferASM(BuiltinNames.rotr, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_rotr: return deferASM(BuiltinNames.rotr, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.f32_abs: return deferASM(BuiltinNames.abs, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_abs: return deferASM(BuiltinNames.abs, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_max: return deferASM(BuiltinNames.max, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_max: return deferASM(BuiltinNames.max, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_min: return deferASM(BuiltinNames.min, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_min: return deferASM(BuiltinNames.min, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_ceil: return deferASM(BuiltinNames.ceil, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_ceil: return deferASM(BuiltinNames.ceil, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_floor: return deferASM(BuiltinNames.floor, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_floor: return deferASM(BuiltinNames.floor, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_copysign: return deferASM(BuiltinNames.copysign, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_copysign: return deferASM(BuiltinNames.copysign, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_nearest: return deferASM(BuiltinNames.nearest, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_nearest: return deferASM(BuiltinNames.nearest, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.i32_reinterpret_f32: return deferASM(BuiltinNames.reinterpret, compiler, Type.i32, operands, Type.f32, reportNode); - case BuiltinNames.i64_reinterpret_f64: return deferASM(BuiltinNames.reinterpret, compiler, Type.i64, operands, Type.f64, reportNode); - case BuiltinNames.f32_reinterpret_i32: return deferASM(BuiltinNames.reinterpret, compiler, Type.f32, operands, Type.i32, reportNode); - case BuiltinNames.f64_reinterpret_i64: return deferASM(BuiltinNames.reinterpret, compiler, Type.f64, operands, Type.i64, reportNode); - case BuiltinNames.f32_sqrt: return deferASM(BuiltinNames.sqrt, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_sqrt: return deferASM(BuiltinNames.sqrt, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_trunc: return deferASM(BuiltinNames.trunc, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_trunc: return deferASM(BuiltinNames.trunc, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.i32_load8_s: return deferASM(BuiltinNames.load, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i32_load8_u: return deferASM(BuiltinNames.load, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_load16_s: return deferASM(BuiltinNames.load, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i32_load16_u: return deferASM(BuiltinNames.load, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_load: return deferASM(BuiltinNames.load, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_load8_s: return deferASM(BuiltinNames.load, compiler, Type.i8, operands, Type.i64, reportNode); - case BuiltinNames.i64_load8_u: return deferASM(BuiltinNames.load, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_load16_s: return deferASM(BuiltinNames.load, compiler, Type.i16, operands, Type.i64, reportNode); - case BuiltinNames.i64_load16_u: return deferASM(BuiltinNames.load, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_load32_s: return deferASM(BuiltinNames.load, compiler, Type.i32, operands, Type.i64, reportNode); - case BuiltinNames.i64_load32_u: return deferASM(BuiltinNames.load, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_load: return deferASM(BuiltinNames.load, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.f32_load: return deferASM(BuiltinNames.load, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_load: return deferASM(BuiltinNames.load, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.i32_store8: return deferASM(BuiltinNames.store, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i32_store16: return deferASM(BuiltinNames.store, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i32_store: return deferASM(BuiltinNames.store, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_store8: return deferASM(BuiltinNames.store, compiler, Type.i8, operands, Type.i64, reportNode); - case BuiltinNames.i64_store16: return deferASM(BuiltinNames.store, compiler, Type.i16, operands, Type.i64, reportNode); - case BuiltinNames.i64_store32: return deferASM(BuiltinNames.store, compiler, Type.i32, operands, Type.i64, reportNode); - case BuiltinNames.i64_store: return deferASM(BuiltinNames.store, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.f32_store: return deferASM(BuiltinNames.store, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_store: return deferASM(BuiltinNames.store, compiler, Type.f64, operands, Type.f64, reportNode); - - case BuiltinNames.i32_atomic_load8_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_load16_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_load: return deferASM(BuiltinNames.atomic_load, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_load8_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_load16_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_load32_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_load: return deferASM(BuiltinNames.atomic_load, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_store8: return deferASM(BuiltinNames.atomic_store, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_store16: return deferASM(BuiltinNames.atomic_store, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_store: return deferASM(BuiltinNames.atomic_store, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_store8: return deferASM(BuiltinNames.atomic_store, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_store16: return deferASM(BuiltinNames.atomic_store, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_store32: return deferASM(BuiltinNames.atomic_store, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_store: return deferASM(BuiltinNames.atomic_store, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_add: return deferASM(BuiltinNames.atomic_add, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_add: return deferASM(BuiltinNames.atomic_add, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_sub: return deferASM(BuiltinNames.atomic_sub, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_sub: return deferASM(BuiltinNames.atomic_sub, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_and: return deferASM(BuiltinNames.atomic_and, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_and: return deferASM(BuiltinNames.atomic_and, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_or: return deferASM(BuiltinNames.atomic_or, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_or: return deferASM(BuiltinNames.atomic_or, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_xor: return deferASM(BuiltinNames.atomic_xor, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_xor: return deferASM(BuiltinNames.atomic_xor, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_xchg: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_xchg: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_cmpxchg: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_cmpxchg: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_wait: return deferASM(BuiltinNames.atomic_wait, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_wait: return deferASM(BuiltinNames.atomic_wait, compiler, Type.i64, operands, Type.i32, reportNode); - - case BuiltinNames.v128_load: return deferASM(BuiltinNames.load, compiler, Type.v128, operands, Type.v128, reportNode); - case BuiltinNames.v128_store: return deferASM(BuiltinNames.store, compiler, Type.v128, operands, Type.v128, reportNode); - - case BuiltinNames.i8x16_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_extract_lane_s: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i8, operands, Type.i8, reportNode); - case BuiltinNames.i8x16_extract_lane_u: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.u8, operands, Type.u8, reportNode); - case BuiltinNames.i8x16_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_min_s: return deferASM(BuiltinNames.v128_min, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_min_u: return deferASM(BuiltinNames.v128_min, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_max_s: return deferASM(BuiltinNames.v128_max, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_max_u: return deferASM(BuiltinNames.v128_max, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_avgr_u: return deferASM(BuiltinNames.v128_avgr, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_add_saturate_s: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_add_saturate_u: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_sub_saturate_s: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_sub_saturate_u: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i8x16_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i8x16_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_lt_s: return deferASM(BuiltinNames.v128_lt, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_lt_u: return deferASM(BuiltinNames.v128_lt, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_le_s: return deferASM(BuiltinNames.v128_le, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_le_u: return deferASM(BuiltinNames.v128_le, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_gt_s: return deferASM(BuiltinNames.v128_gt, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_gt_u: return deferASM(BuiltinNames.v128_gt, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_ge_s: return deferASM(BuiltinNames.v128_ge, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_ge_u: return deferASM(BuiltinNames.v128_ge, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_narrow_i16x8_s: return deferASM(BuiltinNames.v128_narrow, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_narrow_i16x8_u: return deferASM(BuiltinNames.v128_narrow, compiler, Type.u16, operands, Type.v128, reportNode); - - case BuiltinNames.i16x8_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_extract_lane_s: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i16, operands, Type.i16, reportNode); - case BuiltinNames.i16x8_extract_lane_u: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.u16, operands, Type.u16, reportNode); - case BuiltinNames.i16x8_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_min_s: return deferASM(BuiltinNames.v128_min, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_min_u: return deferASM(BuiltinNames.v128_min, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_max_s: return deferASM(BuiltinNames.v128_max, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_max_u: return deferASM(BuiltinNames.v128_max, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_avgr_u: return deferASM(BuiltinNames.v128_avgr, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_add_saturate_s: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_add_saturate_u: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_sub_saturate_s: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_sub_saturate_u: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i16x8_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i16x8_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_lt_s: return deferASM(BuiltinNames.v128_lt, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_lt_u: return deferASM(BuiltinNames.v128_lt, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_le_s: return deferASM(BuiltinNames.v128_le, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_le_u: return deferASM(BuiltinNames.v128_le, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_gt_s: return deferASM(BuiltinNames.v128_gt, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_gt_u: return deferASM(BuiltinNames.v128_gt, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_ge_s: return deferASM(BuiltinNames.v128_ge, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_ge_u: return deferASM(BuiltinNames.v128_ge, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_narrow_i32x4_s: return deferASM(BuiltinNames.v128_narrow, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_narrow_i32x4_u: return deferASM(BuiltinNames.v128_narrow, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_low_i8x16_s: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_low_i8x16_u: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_high_i8x16_s: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_high_i8x16_u: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_load8x8_s: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_load8x8_u: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.u8, operands, Type.v128, reportNode); - - case BuiltinNames.i32x4_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i32x4_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_min_s: return deferASM(BuiltinNames.v128_min, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_min_u: return deferASM(BuiltinNames.v128_min, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_max_s: return deferASM(BuiltinNames.v128_max, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_max_u: return deferASM(BuiltinNames.v128_max, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_dot_i16x8_s: return deferASM(BuiltinNames.v128_dot, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i32x4_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i32x4_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_lt_s: return deferASM(BuiltinNames.v128_lt, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_lt_u: return deferASM(BuiltinNames.v128_lt, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_le_s: return deferASM(BuiltinNames.v128_le, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_le_u: return deferASM(BuiltinNames.v128_le, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_gt_s: return deferASM(BuiltinNames.v128_gt, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_gt_u: return deferASM(BuiltinNames.v128_gt, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_ge_s: return deferASM(BuiltinNames.v128_ge, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_ge_u: return deferASM(BuiltinNames.v128_ge, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_trunc_sat_f32x4_s: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_trunc_sat_f32x4_u: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_low_i16x8_s: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_low_i16x8_u: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_high_i16x8_s: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_high_i16x8_u: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_load16x4_s: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_load16x4_u: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.u16, operands, Type.v128, reportNode); - - case BuiltinNames.i64x2_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i64x2_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i64, operands, Type.i32, reportNode); - case BuiltinNames.i64x2_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i64, operands, Type.i32, reportNode); - case BuiltinNames.i64x2_trunc_sat_f64x2_s: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_trunc_sat_f64x2_u: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.u64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_load32x2_s: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_load32x2_u: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.u32, operands, Type.v128, reportNode); - - case BuiltinNames.f32x4_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f32x4_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_add: return deferASM(BuiltinNames.v128_add, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_div: return deferASM(BuiltinNames.v128_div, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_min: return deferASM(BuiltinNames.v128_min, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_max: return deferASM(BuiltinNames.v128_max, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_abs: return deferASM(BuiltinNames.v128_abs, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_sqrt: return deferASM(BuiltinNames.v128_sqrt, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_lt: return deferASM(BuiltinNames.v128_lt, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_le: return deferASM(BuiltinNames.v128_le, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_gt: return deferASM(BuiltinNames.v128_gt, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_ge: return deferASM(BuiltinNames.v128_ge, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_convert_i32x4_s: return deferASM(BuiltinNames.v128_convert, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_convert_i32x4_u: return deferASM(BuiltinNames.v128_convert, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_qfma: return deferASM(BuiltinNames.v128_qfma, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_qfms: return deferASM(BuiltinNames.v128_qfms, compiler, Type.f32, operands, Type.v128, reportNode); - - case BuiltinNames.f64x2_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f64x2_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_add: return deferASM(BuiltinNames.v128_add, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_div: return deferASM(BuiltinNames.v128_div, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_min: return deferASM(BuiltinNames.v128_min, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_max: return deferASM(BuiltinNames.v128_max, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_abs: return deferASM(BuiltinNames.v128_abs, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_sqrt: return deferASM(BuiltinNames.v128_sqrt, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_lt: return deferASM(BuiltinNames.v128_lt, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_le: return deferASM(BuiltinNames.v128_le, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_gt: return deferASM(BuiltinNames.v128_gt, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_ge: return deferASM(BuiltinNames.v128_ge, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_convert_i64x2_s: return deferASM(BuiltinNames.v128_convert, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_convert_i64x2_u: return deferASM(BuiltinNames.v128_convert, compiler, Type.u64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_qfma: return deferASM(BuiltinNames.v128_qfma, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_qfms: return deferASM(BuiltinNames.v128_qfms, compiler, Type.f64, operands, Type.v128, reportNode); - - case BuiltinNames.v8x16_shuffle: return deferASM(BuiltinNames.v128_shuffle, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.v8x16_swizzle: return deferASM(BuiltinNames.v128_swizzle, compiler, null, operands, Type.v128, reportNode); - case BuiltinNames.v8x16_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.v16x8_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.v32x4_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.v64x2_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u64, operands, Type.v128, reportNode); - } - /* tslint:enable:max-line-length */ - return 0; -} - -/** A helper for deferring inline-assembler-like calls to built-in functions. */ -function deferASM( - name: string, - compiler: Compiler, - typeArgument: Type | null, - operands: Expression[], - contextualType: Type, - reportNode: CallExpression -): ExpressionRef { - assert(compiler.program.elementsByName.has(name)); - var prototype = compiler.program.elementsByName.get(name)!; - assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE); - return compileCall( - compiler, - prototype, - typeArgument ? [ typeArgument ] : null, - operands, - contextualType, - reportNode, - /* isAsm */ true +// v128.narrow(a: v128, b: v128) -> v128 +function builtin_v128_narrow(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I16: return module.binary(BinaryOp.NarrowI16x8ToI8x16, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.NarrowU16x8ToU8x16, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.NarrowI32x4ToI16x8, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.NarrowU32x4ToU16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.narrow", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_narrow, builtin_v128_narrow); + +// v128.neg(a: v128) -> v128 +function builtin_v128_neg(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.NegI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.NegI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.NegI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.NegI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.NegI64x2 + : UnaryOp.NegI32x4, + arg0 + ); + } + case TypeKind.F32: return module.unary(UnaryOp.NegF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.NegF64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.neg", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_neg, builtin_v128_neg); + +// v128.abs(a: v128) -> v128 +function builtin_v128_abs(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.unary(UnaryOp.AbsF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.AbsF64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.abs", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_abs, builtin_v128_abs); + +// v128.sqrt(a: v128) -> v128 +function builtin_v128_sqrt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.unary(UnaryOp.SqrtF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.SqrtF64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.sqrt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_sqrt, builtin_v128_sqrt); + +// v128.convert(a: v128) -> v128 +function builtin_v128_convert(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I32: return module.unary(UnaryOp.ConvertI32x4ToF32x4, arg0); + case TypeKind.U32: return module.unary(UnaryOp.ConvertU32x4ToF32x4, arg0); + case TypeKind.I64: return module.unary(UnaryOp.ConvertI64x2ToF64x2, arg0); + case TypeKind.U64: return module.unary(UnaryOp.ConvertU64x2ToF64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.convert", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_convert, builtin_v128_convert); + +// v128.trunc_sat(a: v128) -> v128 +function builtin_v128_trunc_sat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I32: return module.unary(UnaryOp.TruncSatF32x4ToI32x4, arg0); + case TypeKind.U32: return module.unary(UnaryOp.TruncSatF32x4ToU32x4, arg0); + case TypeKind.I64: return module.unary(UnaryOp.TruncSatF64x2ToI64x2, arg0); + case TypeKind.U64: return module.unary(UnaryOp.TruncSatF64x2ToU64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.trunc_sat", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_trunc_sat, builtin_v128_trunc_sat); + +// v128.widen_low(a: v128) -> v128 +function builtin_v128_widen_low(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.unary(UnaryOp.WidenLowI8x16ToI16x8, arg0); + case TypeKind.U8: return module.unary(UnaryOp.WidenLowU8x16ToU16x8, arg0); + case TypeKind.I16: return module.unary(UnaryOp.WidenLowI16x8ToI32x4, arg0); + case TypeKind.U16: return module.unary(UnaryOp.WidenLowU16x8ToU32x4, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.widen_low", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_widen_low, builtin_v128_widen_low); + +// v128.widen_high(a: v128) -> v128 +function builtin_v128_widen_high(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.unary(UnaryOp.WidenHighI8x16ToI16x8, arg0); + case TypeKind.U8: return module.unary(UnaryOp.WidenHighU8x16ToU16x8, arg0); + case TypeKind.I16: return module.unary(UnaryOp.WidenHighI16x8ToI32x4, arg0); + case TypeKind.U16: return module.unary(UnaryOp.WidenHighU16x8ToU32x4, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.widen_high", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_widen_high, builtin_v128_widen_high); + +// v128.shl(a: v128, b: i32) -> v128 +function builtin_v128_shl(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShlI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShlI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShlI32x4, arg0, arg1); + case TypeKind.I64: + case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShlI64x2, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.simd_shift( + compiler.options.isWasm64 + ? SIMDShiftOp.ShlI64x2 + : SIMDShiftOp.ShlI32x4, + arg0, arg1 + ); + } + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.shl", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_shl, builtin_v128_shl); + +// v128.shr(a: v128, b: i32) -> v128 +function builtin_v128_shr(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.simd_shift(SIMDShiftOp.ShrI8x16, arg0, arg1); + case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShrU8x16, arg0, arg1); + case TypeKind.I16: return module.simd_shift(SIMDShiftOp.ShrI16x8, arg0, arg1); + case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShrU16x8, arg0, arg1); + case TypeKind.I32: return module.simd_shift(SIMDShiftOp.ShrI32x4, arg0, arg1); + case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShrU32x4, arg0, arg1); + case TypeKind.I64: return module.simd_shift(SIMDShiftOp.ShrI64x2, arg0, arg1); + case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShrU64x2, arg0, arg1); + case TypeKind.ISIZE: { + return module.simd_shift( + compiler.options.isWasm64 + ? SIMDShiftOp.ShrI64x2 + : SIMDShiftOp.ShrI32x4, + arg0, arg1 + ); + } + case TypeKind.USIZE: { + return module.simd_shift( + compiler.options.isWasm64 + ? SIMDShiftOp.ShrU64x2 + : SIMDShiftOp.ShrU32x4, + arg0, arg1 + ); + } + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.shr", type.toString() ); + return module.unreachable(); } +builtins.set(BuiltinNames.v128_shr, builtin_v128_shr); + +function builtin_v128_bitwise_binary(ctx: BuiltinContext, op: BinaryOp): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + return module.binary(op, arg0, arg1); +} + +// v128.and(a: v128, b: v128) -> v128 +function builtin_v128_and(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.AndV128); +} +builtins.set(BuiltinNames.v128_and, builtin_v128_and); + +// v128.or(a: v128, b: v128) -> v128 +function builtin_v128_or(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.OrV128); +} +builtins.set(BuiltinNames.v128_or, builtin_v128_or); + +// v128.xor(a: v128, b: v128) -> v128 +function builtin_v128_xor(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.XorV128); +} +builtins.set(BuiltinNames.v128_xor, builtin_v128_xor); + +// v128.andnot(a: v128, b: v128) -> v128 +function builtin_v128_andnot(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.AndNotV128); +} +builtins.set(BuiltinNames.v128_andnot, builtin_v128_andnot); + +function builtin_v128_bitwise_unary(ctx: BuiltinContext, op: UnaryOp): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + return module.unary(op, arg0); +} + +// v128.not(a: v128) -> v128 +function builtin_v128_not(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_unary(ctx, UnaryOp.NotV128); +} +builtins.set(BuiltinNames.v128_not, builtin_v128_not); + +function builtin_v128_bitwise_ternary(ctx: BuiltinContext, op: SIMDTernaryOp): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); + return module.simd_ternary(op, arg0, arg1, arg2); +} + +// v128.bitselect(v1: v128, v2: v128, c: v128) -> v128 +function builtin_v128_bitselect(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_ternary(ctx, SIMDTernaryOp.Bitselect); +} +builtins.set(BuiltinNames.v128_bitselect, builtin_v128_bitselect); + +// v128.any_true(a: v128) -> bool +function builtin_v128_any_true(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.AnyTrueI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.AnyTrueI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.AnyTrueI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.AnyTrueI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.AnyTrueI64x2 + : UnaryOp.AnyTrueI32x4, + arg0 + ); + } + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.any_true", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_any_true, builtin_v128_any_true); + +// v128.all_true(a: v128) -> bool +function builtin_v128_all_true(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.AllTrueI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.AllTrueI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.AllTrueI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.AllTrueI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.AllTrueI64x2 + : UnaryOp.AllTrueI32x4, + arg0 + ); + } + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.all_true", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_all_true, builtin_v128_all_true); + +// v128.qfma(a: v128, b: v128, c: v128) -> v128 +function builtin_v128_qfma(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMAF32x4, arg0, arg1, arg2); + case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMAF64x2, arg0, arg1, arg2); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.qfma", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_qfma, builtin_v128_qfma); + +// v128.qfms(a: v128, b: v128, c: v128) -> v128 +function builtin_v128_qfms(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMSF32x4, arg0, arg1, arg2); + case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMSF64x2, arg0, arg1, arg2); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.qfms", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_qfms, builtin_v128_qfms); + +// === Internal runtime ======================================================================= + +// __visit_globals(cookie: u32) -> void +function builtin_visit_globals(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) // cookie + ) { + compiler.currentType = Type.void; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.u32, Constraints.CONV_IMPLICIT); + compiler.runtimeFeatures |= RuntimeFeatures.visitGlobals; + compiler.currentType = Type.void; + return module.call(BuiltinNames.visit_globals, [ arg0 ], NativeType.None); +} +builtins.set(BuiltinNames.visit_globals, builtin_visit_globals); + +// __visit_members(ref: usize, cookie: u32) -> void +function builtin_visit_members(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) // ref, cookie + ) { + compiler.currentType = Type.void; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.u32, Constraints.CONV_IMPLICIT); + compiler.runtimeFeatures |= RuntimeFeatures.visitMembers; + compiler.currentType = Type.void; + return module.call(BuiltinNames.visit_members, [ arg0, arg1 ], NativeType.None); +} +builtins.set(BuiltinNames.visit_members, builtin_visit_members); + +// === Inline assembler ======================================================================= + +// TODO: Operators can't be just deferred (don't have a corresponding generic built-in) +// add, sub, mul, div_s, div_u, rem_s, rem_u +// and, or, xor, shl, shr_u, shr_s +// eq, eqz, ne, lt_s, lt_u, le_s, le_u, gt_s, gt_u, ge_s, ge_u + +// i32.clz -> clz +function builtin_i32_clz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_clz(ctx); +} +builtins.set(BuiltinNames.i32_clz, builtin_i32_clz); + +// i64.clz -> clz +function builtin_i64_clz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_clz(ctx); +} +builtins.set(BuiltinNames.i64_clz, builtin_i64_clz); + +// i32.ctz -> ctz +function builtin_i32_ctz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_ctz(ctx); +} +builtins.set(BuiltinNames.i32_ctz, builtin_i32_ctz); + +// i64.ctz -> ctz +function builtin_i64_ctz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_ctz(ctx); +} +builtins.set(BuiltinNames.i64_ctz, builtin_i64_ctz); + +// i32.popcnt -> popcnt +function builtin_i32_popcnt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_popcnt(ctx); +} +builtins.set(BuiltinNames.i32_popcnt, builtin_i32_popcnt); + +// i64.popcnt -> popcnt +function builtin_i64_popcnt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_popcnt(ctx); +} +builtins.set(BuiltinNames.i64_popcnt, builtin_i64_popcnt); + +// i32.rotl -> rotl +function builtin_i32_rotl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_rotl(ctx); +} +builtins.set(BuiltinNames.i32_rotl, builtin_i32_rotl); + +// i64.rotl -> rotl +function builtin_i64_rotl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_rotl(ctx); +} +builtins.set(BuiltinNames.i64_rotl, builtin_i64_rotl); + +// i32.rotr -> rotr +function builtin_i32_rotr(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_rotr(ctx); +} +builtins.set(BuiltinNames.i32_rotr, builtin_i32_rotr); + +// i64.rotr -> rotr +function builtin_i64_rotr(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_rotr(ctx); +} +builtins.set(BuiltinNames.i64_rotr, builtin_i64_rotr); + +// f32.abs -> abs +function builtin_f32_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_abs(ctx); +} +builtins.set(BuiltinNames.f32_abs, builtin_f32_abs); + +// f64.abs -> abs +function builtin_f64_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_abs(ctx); +} +builtins.set(BuiltinNames.f64_abs, builtin_f64_abs); + +// f32.max -> max +function builtin_f32_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_max(ctx); +} +builtins.set(BuiltinNames.f32_max, builtin_f32_max); + +// f64.max -> max +function builtin_f64_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_max(ctx); +} +builtins.set(BuiltinNames.f64_max, builtin_f64_max); + +// f32.min -> min +function builtin_f32_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_min(ctx); +} +builtins.set(BuiltinNames.f32_min, builtin_f32_min); + +// f64.min -> min +function builtin_f64_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_min(ctx); +} +builtins.set(BuiltinNames.f64_min, builtin_f64_min); + +// f32.ceil -> ceil +function builtin_f32_ceil(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_ceil(ctx); +} +builtins.set(BuiltinNames.f32_ceil, builtin_f32_ceil); + +// f64.ceil -> ceil +function builtin_f64_ceil(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_ceil(ctx); +} +builtins.set(BuiltinNames.f64_ceil, builtin_f64_ceil); + +// f32.floor -> floor +function builtin_f32_floor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_floor(ctx); +} +builtins.set(BuiltinNames.f32_floor, builtin_f32_floor); + +// f64.floor -> floor +function builtin_f64_floor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_floor(ctx); +} +builtins.set(BuiltinNames.f64_floor, builtin_f64_floor); + +// f32.copysign -> copysign +function builtin_f32_copysign(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_copysign(ctx); +} +builtins.set(BuiltinNames.f32_copysign, builtin_f32_copysign); + +// f64.copysign -> copysign +function builtin_f64_copysign(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_copysign(ctx); +} +builtins.set(BuiltinNames.f64_copysign, builtin_f64_copysign); + +// f32.nearest -> nearest +function builtin_f32_nearest(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_nearest(ctx); +} +builtins.set(BuiltinNames.f32_nearest, builtin_f32_nearest); + +// f64.nearest -> nearest +function builtin_f64_nearest(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_nearest(ctx); +} +builtins.set(BuiltinNames.f64_nearest, builtin_f64_nearest); + +// i32.reinterpret_f32 -> reinterpret +function builtin_i32_reinterpret_f32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.f32; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.i32_reinterpret_f32, builtin_i32_reinterpret_f32); + +// i64.reinterpret_f64 -> reinterpret +function builtin_i64_reinterpret_f64(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.f64; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.i64_reinterpret_f64, builtin_i64_reinterpret_f64); + +// f32.reinterpret_i32 -> reinterpret +function builtin_f32_reinterpret_i32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.i32; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.f32_reinterpret_i32, builtin_f32_reinterpret_i32); + +// f64.reinterpret_i64 -> reinterpret +function builtin_f64_reinterpret_i64(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.i64; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.f64_reinterpret_i64, builtin_f64_reinterpret_i64); + +// f32.sqrt -> sqrt +function builtin_f32_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_sqrt(ctx); +} +builtins.set(BuiltinNames.f32_sqrt, builtin_f32_sqrt); + +// f64.sqrt -> sqrt +function builtin_f64_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_sqrt(ctx); +} +builtins.set(BuiltinNames.f64_sqrt, builtin_f64_sqrt); + +// f32.trunc -> trunc +function builtin_f32_trunc(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_trunc(ctx); +} +builtins.set(BuiltinNames.f32_trunc, builtin_f32_trunc); + +// f64.trunc -> trunc +function builtin_f64_trunc(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_trunc(ctx); +} +builtins.set(BuiltinNames.f64_trunc, builtin_f64_trunc); + +// i32.load8_s -> load +function builtin_i32_load8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load8_s, builtin_i32_load8_s); + +// i32.load8_u -> load +function builtin_i32_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load8_u, builtin_i32_load8_u); + +// i32.load16_s -> load +function builtin_i32_load16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load16_s, builtin_i32_load16_s); + +// i32.load16_u -> load +function builtin_i32_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load16_u, builtin_i32_load16_u); + +// i32.load -> load +function builtin_i32_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load, builtin_i32_load); + +// i64.load8_s -> load +function builtin_i64_load8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load8_s, builtin_i64_load8_s); + +// i64.load8_u -> load +function builtin_i64_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load8_u, builtin_i64_load8_u); + +// i64.load16_s -> load +function builtin_i64_load16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load16_s, builtin_i64_load16_s); + +// i64.load16_u -> load +function builtin_i64_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load16_u, builtin_i64_load16_u); + +// i64.load32_s -> load +function builtin_i64_load32_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load32_s, builtin_i64_load32_s); + +// i64.load32_u -> load +function builtin_i64_load32_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load32_u, builtin_i64_load32_u); + +// i64.load -> load +function builtin_i64_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load, builtin_i64_load); + +// f32.load -> load +function builtin_f32_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.f32_load, builtin_f32_load); + +// f64.load -> load +function builtin_f64_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.f64_load, builtin_f64_load); + +// i32.store8 -> store +function builtin_i32_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i32_store8, builtin_i32_store8); + +// i32.store16 -> store +function builtin_i32_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i32_store16, builtin_i32_store16); + +// i32.store -> store +function builtin_i32_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i32_store, builtin_i32_store); + +// i64.store8 -> store +function builtin_i64_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store8, builtin_i64_store8); + +// i64.store16 -> store +function builtin_i64_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store16, builtin_i64_store16); + +// i64.store32 -> store +function builtin_i64_store32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store32, builtin_i64_store32); + +// i64.store -> store +function builtin_i64_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store, builtin_i64_store); + +// f32.store -> store +function builtin_f32_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.f32_store, builtin_f32_store); + +// f64.store -> store +function builtin_f64_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.f64_store, builtin_f64_store); + +// i32.atomic.load8_u -> atomic.load +function builtin_i32_atomic_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i32_atomic_load8_u, builtin_i32_atomic_load8_u); + +// i32.atomic.load16_u -> atomic.load +function builtin_i32_atomic_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i32_atomic_load16_u, builtin_i32_atomic_load16_u); + +// i32.atomic.load -> atomic.load +function builtin_i32_atomic_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i32_atomic_load, builtin_i32_atomic_load); + +// i64.atomic.load8_u -> atomic.load +function builtin_i64_atomic_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load8_u, builtin_i64_atomic_load8_u); + +// i64.atomic.load16_u -> atomic.load +function builtin_i64_atomic_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load16_u, builtin_i64_atomic_load16_u); + +// i64.atomic.load32_u -> atomic.load +function builtin_i64_atomic_load32_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load32_u, builtin_i64_atomic_load32_u); + +// i64.atomic.load -> atomic.load +function builtin_i64_atomic_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load, builtin_i64_atomic_load); + +// i32.atomic.store8 -> atomic.store +function builtin_i32_atomic_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i32_atomic_store8, builtin_i32_atomic_store8); + +// i32.atomic.store16 -> atomic.store +function builtin_i32_atomic_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i32_atomic_store16, builtin_i32_atomic_store16); + +// i32.atomic.store -> atomic.store +function builtin_i32_atomic_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i32_atomic_store, builtin_i32_atomic_store); + +// i64.atomic.store8 -> atomic.store +function builtin_i64_atomic_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store8, builtin_i64_atomic_store8); + +// i64.atomic.store16 -> atomic.store +function builtin_i64_atomic_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store16, builtin_i64_atomic_store16); + +// i64.atomic.store32 -> atomic.store +function builtin_i64_atomic_store32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store32, builtin_i64_atomic_store32); + +// i64.atomic.store -> atomic.store +function builtin_i64_atomic_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store, builtin_i64_atomic_store); + +// i32.atomic.rmw8.add_u -> atomic.add +function builtin_i32_atomic_rmw8_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_add_u, builtin_i32_atomic_rmw8_add_u); + +// i32.atomic.rmw16.add_u -> atomic.add +function builtin_i32_atomic_rmw16_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_add_u, builtin_i32_atomic_rmw16_add_u); + +// i32.atomic.rmw.add -> atomic.add +function builtin_i32_atomic_rmw_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_add, builtin_i32_atomic_rmw_add); + +// i64.atomic.rmw8.add_u -> atomic.add +function builtin_i64_atomic_rmw8_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_add_u, builtin_i64_atomic_rmw8_add_u); + +// i64.atomic.rmw16.add_u -> atomic.add +function builtin_i64_atomic_rmw16_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_add_u, builtin_i64_atomic_rmw16_add_u); + +// i64.atomic.rmw32.add_u -> atomic.add +function builtin_i64_atomic_rmw32_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_add_u, builtin_i64_atomic_rmw32_add_u); + +// i64.atomic.rmw.add -> atomic.add +function builtin_i64_atomic_rmw_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_add, builtin_i64_atomic_rmw_add); + +// i32.atomic.rmw8.sub_u -> atomic.sub +function builtin_i32_atomic_rmw8_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_sub_u, builtin_i32_atomic_rmw8_sub_u); + +// i32.atomic.rmw16.sub_u -> atomic.sub +function builtin_i32_atomic_rmw16_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_sub_u, builtin_i32_atomic_rmw16_sub_u); + +// i32.atomic.rmw.sub -> atomic.sub +function builtin_i32_atomic_rmw_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_sub, builtin_i32_atomic_rmw_sub); + +// i64.atomic.rmw8.sub_u -> atomic.sub +function builtin_i64_atomic_rmw8_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_sub_u, builtin_i64_atomic_rmw8_sub_u); + +// i64.atomic.rmw16.sub_u -> atomic.sub +function builtin_i64_atomic_rmw16_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_sub_u, builtin_i64_atomic_rmw16_sub_u); + +// i64.atomic.rmw32.sub_u -> atomic.sub +function builtin_i64_atomic_rmw32_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_sub_u, builtin_i64_atomic_rmw32_sub_u); + +// i64.atomic.rmw.sub -> atomic.sub +function builtin_i64_atomic_rmw_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_sub, builtin_i64_atomic_rmw_sub); + +// i32.atomic.rmw8.and_u -> atomic.and +function builtin_i32_atomic_rmw8_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_and_u, builtin_i32_atomic_rmw8_and_u); + +// i32.atomic.rmw16.and_u -> atomic.and +function builtin_i32_atomic_rmw16_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_and_u, builtin_i32_atomic_rmw16_and_u); + +// i32.atomic.rmw.and -> atomic.and +function builtin_i32_atomic_rmw_and(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_and, builtin_i32_atomic_rmw_and); + +// i64.atomic.rmw8.and_u -> atomic.and +function builtin_i64_atomic_rmw8_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_and_u, builtin_i64_atomic_rmw8_and_u); + +// i64.atomic.rmw16.and_u -> atomic.and +function builtin_i64_atomic_rmw16_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_and_u, builtin_i64_atomic_rmw16_and_u); + +// i64.atomic.rmw32.and_u -> atomic.and +function builtin_i64_atomic_rmw32_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_and_u, builtin_i64_atomic_rmw32_and_u); + +// i64.atomic.rmw.and -> atomic.and +function builtin_i64_atomic_rmw_and(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_and, builtin_i64_atomic_rmw_and); + +// i32.atomic.rmw8.or_u -> atomic.or +function builtin_i32_atomic_rmw8_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_or_u, builtin_i32_atomic_rmw8_or_u); + +// i32.atomic.rmw16.or_u -> +function builtin_i32_atomic_rmw16_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_or_u, builtin_i32_atomic_rmw16_or_u); + +// i32.atomic.rmw.or -> atomic.or +function builtin_i32_atomic_rmw_or(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_or, builtin_i32_atomic_rmw_or); + +// i64.atomic.rmw8.or_u -> atomic.or +function builtin_i64_atomic_rmw8_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_or_u, builtin_i64_atomic_rmw8_or_u); + +// i64.atomic.rmw16.or_u -> atomic.or +function builtin_i64_atomic_rmw16_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_or_u, builtin_i64_atomic_rmw16_or_u); + +// i64.atomic.rmw32.or_u -> atomic.or +function builtin_i64_atomic_rmw32_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_or_u, builtin_i64_atomic_rmw32_or_u); + +// i64.atomic.rmw.or -> atomic.or +function builtin_i64_atomic_rmw_or(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_or, builtin_i64_atomic_rmw_or); + +// i32.atomic.rmw8.xor_u -> atomic.xor +function builtin_i32_atomic_rmw8_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_xor_u, builtin_i32_atomic_rmw8_xor_u); + +// i32.atomic.rmw16.xor_u -> atomic.xor +function builtin_i32_atomic_rmw16_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_xor_u, builtin_i32_atomic_rmw16_xor_u); + +// i32.atomic.rmw.xor -> atomic.xor +function builtin_i32_atomic_rmw_xor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_xor, builtin_i32_atomic_rmw_xor); + +// i64.atomic.rmw8.xor_u -> atomic.xor +function builtin_i64_atomic_rmw8_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_xor_u, builtin_i64_atomic_rmw8_xor_u); + +// i64.atomic.rmw16.xor_u -> atomic.xor +function builtin_i64_atomic_rmw16_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_xor_u, builtin_i64_atomic_rmw16_xor_u); + +// i64.atomic.rmw32.xor_u -> atomic.xor +function builtin_i64_atomic_rmw32_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_xor_u, builtin_i64_atomic_rmw32_xor_u); + +// i64.atomic.rmw.xor -> atomic.xor +function builtin_i64_atomic_rmw_xor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_xor, builtin_i64_atomic_rmw_xor); + +// i32.atomic.rmw8.xchg_u -> atomic.xchg +function builtin_i32_atomic_rmw8_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_xchg_u, builtin_i32_atomic_rmw8_xchg_u); + +// i32.atomic.rmw16.xchg_u -> atomic.xchg +function builtin_i32_atomic_rmw16_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_xchg_u, builtin_i32_atomic_rmw16_xchg_u); + +// i32.atomic.rmw.xchg -> atomic.xchg +function builtin_i32_atomic_rmw_xchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_xchg, builtin_i32_atomic_rmw_xchg); + +// i64.atomic.rmw8.xchg_u -> atomic.xchg +function builtin_i64_atomic_rmw8_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_xchg_u, builtin_i64_atomic_rmw8_xchg_u); + +// i64.atomic.rmw16.xchg_u -> atomic.xchg +function builtin_i64_atomic_rmw16_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_xchg_u, builtin_i64_atomic_rmw16_xchg_u); + +// i64.atomic.rmw32.xchg_u -> atomic.xchg +function builtin_i64_atomic_rmw32_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_xchg_u, builtin_i64_atomic_rmw32_xchg_u); + +// i64.atomic.rmw.xchg -> atomic.xchg +function builtin_i64_atomic_rmw_xchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_xchg, builtin_i64_atomic_rmw_xchg); + +// i32.atomic.rmw8.cmpxchg_u -> atomic.cmpxchg +function builtin_i32_atomic_rmw8_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_cmpxchg_u, builtin_i32_atomic_rmw8_cmpxchg_u); + +// i32.atomic.rmw16.cmpxchg_u -> atomic.cmpxchg +function builtin_i32_atomic_rmw16_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_cmpxchg_u, builtin_i32_atomic_rmw16_cmpxchg_u); + +// i32.atomic.rmw.cmpxchg -> atomic.cmpxchg +function builtin_i32_atomic_rmw_cmpxchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_cmpxchg, builtin_i32_atomic_rmw_cmpxchg); + +// i64.atomic.rmw8.cmpxchg_u -> atomic.cmpxchg +function builtin_i64_atomic_rmw8_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_cmpxchg_u, builtin_i64_atomic_rmw8_cmpxchg_u); + +// i64.atomic.rmw16.cmpxchg_u -> atomic.cmpxchg +function builtin_i64_atomic_rmw16_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_cmpxchg_u, builtin_i64_atomic_rmw16_cmpxchg_u); + +// i64.atomic.rmw32.cmpxchg_u -> atomic.cmpxchg +function builtin_i64_atomic_rmw32_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_cmpxchg_u, builtin_i64_atomic_rmw32_cmpxchg_u); + +// i64.atomic.rmw.cmpxchg -> atomic.cmpxchg +function builtin_i64_atomic_rmw_cmpxchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_cmpxchg, builtin_i64_atomic_rmw_cmpxchg); + +// i32.wait -> atomic.wait +function builtin_i32_wait(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + return builtin_atomic_wait(ctx); +} +builtins.set(BuiltinNames.i32_wait, builtin_i32_wait); + +// i64.wait -> atomic.wait +function builtin_i64_wait(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_wait(ctx); +} +builtins.set(BuiltinNames.i64_wait, builtin_i64_wait); + +// v128.load -> load +function builtin_v128_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.v128 ]; + ctx.contextualType = Type.v128; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.v128_load, builtin_v128_load); + +// v128.store -> store +function builtin_v128_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.v128 ]; + ctx.contextualType = Type.v128; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.v128_store, builtin_v128_store); + +// i8x16_splat -> v128.splat +function builtin_i8x16_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i8x16_splat, builtin_i8x16_splat); + +// i8x16.extract_lane_s -> v128.extract_lane +function builtin_i8x16_extract_lane_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i8x16_extract_lane_s, builtin_i8x16_extract_lane_s); + +// i8x16.extract_lane_u -> v128.extract_lane +function builtin_i8x16_extract_lane_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i8x16_extract_lane_u, builtin_i8x16_extract_lane_u); + +// i8x16.replace_lane -> v128.replace_lane +function builtin_i8x16_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i8x16_replace_lane, builtin_i8x16_replace_lane); + +// i8x16.add -> v128.add +function builtin_i8x16_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i8x16_add, builtin_i8x16_add); + +// i8x16.sub -> v128.sub +function builtin_i8x16_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i8x16_sub, builtin_i8x16_sub); + +// i8x16.mul -> v128.mul +function builtin_i8x16_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.i8x16_mul, builtin_i8x16_mul); + +// i8x16.min_s -> v128.min +function builtin_i8x16_min_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i8x16_min_s, builtin_i8x16_min_s); + +// i8x16.min_u -> v128.min +function builtin_i8x16_min_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i8x16_min_u, builtin_i8x16_min_u); + +// i8x16.max_s -> v128.max +function builtin_i8x16_max_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i8x16_max_s, builtin_i8x16_max_s); + +// i8x16.max_u -> v128.max +function builtin_i8x16_max_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i8x16_max_u, builtin_i8x16_max_u); + +// i8x16.avgr_u -> v128.avgr +function builtin_i8x16_avgr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_avgr(ctx); +} +builtins.set(BuiltinNames.i8x16_avgr_u, builtin_i8x16_avgr_u); + +// i8x16.neg -> v128.neg +function builtin_i8x16_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i8x16_neg, builtin_i8x16_neg); + +// i8x16.add_saturate_s -> v128.add_saturate +function builtin_i8x16_add_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_add_saturate_s, builtin_i8x16_add_saturate_s); + +// i8x16.add_saturate_u -> v128.add_saturate +function builtin_i8x16_add_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_add_saturate_u, builtin_i8x16_add_saturate_u); + +// i8x16.sub_saturate_s -> v128.sub_saturate +function builtin_i8x16_sub_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_sub_saturate_s, builtin_i8x16_sub_saturate_s); + +// i8x16.sub_saturate_u -> v128.sub_saturate +function builtin_i8x16_sub_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_sub_saturate_u, builtin_i8x16_sub_saturate_u); + +// i8x16.shl -> v128.shl +function builtin_i8x16_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i8x16_shl, builtin_i8x16_shl); + +// i8x16.shr_s -> v128.shr +function builtin_i8x16_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i8x16_shr_s, builtin_i8x16_shr_s); + +// i8x16.shr_u -> v128.shr +function builtin_i8x16_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i8x16_shr_u, builtin_i8x16_shr_u); + +function builtin_i8x16_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i8x16_any_true, builtin_i8x16_any_true); + +function builtin_i8x16_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i8x16_all_true, builtin_i8x16_all_true); + +function builtin_i8x16_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.i8x16_eq, builtin_i8x16_eq); + +function builtin_i8x16_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.i8x16_ne, builtin_i8x16_ne); + +function builtin_i8x16_lt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i8x16_lt_s, builtin_i8x16_lt_s); + +function builtin_i8x16_lt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i8x16_lt_u, builtin_i8x16_lt_u); + +function builtin_i8x16_le_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i8x16_le_s, builtin_i8x16_le_s); + +function builtin_i8x16_le_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i8x16_le_u, builtin_i8x16_le_u); + +function builtin_i8x16_gt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i8x16_gt_s, builtin_i8x16_gt_s); + +function builtin_i8x16_gt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i8x16_gt_u, builtin_i8x16_gt_u); + +function builtin_i8x16_ge_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i8x16_ge_s, builtin_i8x16_ge_s); + +function builtin_i8x16_ge_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i8x16_ge_u, builtin_i8x16_ge_u); + +function builtin_i8x16_narrow_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i8x16_narrow_i16x8_s, builtin_i8x16_narrow_i16x8_s); + +function builtin_i8x16_narrow_i16x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i8x16_narrow_i16x8_u, builtin_i8x16_narrow_i16x8_u); + +function builtin_i16x8_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i16x8_splat, builtin_i16x8_splat); + +function builtin_i16x8_extract_lane_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i16; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i16x8_extract_lane_s, builtin_i16x8_extract_lane_s); + +function builtin_i16x8_extract_lane_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.u16; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i16x8_extract_lane_u, builtin_i16x8_extract_lane_u); + +function builtin_i16x8_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i16x8_replace_lane, builtin_i16x8_replace_lane); + +function builtin_i16x8_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i16x8_add, builtin_i16x8_add); + +function builtin_i16x8_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i16x8_sub, builtin_i16x8_sub); + +function builtin_i16x8_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.i16x8_mul, builtin_i16x8_mul); + +function builtin_i16x8_min_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i16x8_min_s, builtin_i16x8_min_s); + +function builtin_i16x8_min_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i16x8_min_u, builtin_i16x8_min_u); + +function builtin_i16x8_max_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i16x8_max_s, builtin_i16x8_max_s); + +function builtin_i16x8_max_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i16x8_max_u, builtin_i16x8_max_u); + +function builtin_i16x8_avgr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_avgr(ctx); +} +builtins.set(BuiltinNames.i16x8_avgr_u, builtin_i16x8_avgr_u); + +function builtin_i16x8_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i16x8_neg, builtin_i16x8_neg); + +function builtin_i16x8_add_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_add_saturate_s, builtin_i16x8_add_saturate_s); + +function builtin_i16x8_add_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_add_saturate_u, builtin_i16x8_add_saturate_u); + +function builtin_i16x8_sub_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_sub_saturate_s, builtin_i16x8_sub_saturate_s); + +function builtin_i16x8_sub_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_sub_saturate_u, builtin_i16x8_sub_saturate_u); + +function builtin_i16x8_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i16x8_shl, builtin_i16x8_shl); + +function builtin_i16x8_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i16x8_shr_s, builtin_i16x8_shr_s); + +function builtin_i16x8_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i16x8_shr_u, builtin_i16x8_shr_u); + +function builtin_i16x8_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i16x8_any_true, builtin_i16x8_any_true); + +function builtin_i16x8_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i16x8_all_true, builtin_i16x8_all_true); + +function builtin_i16x8_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.i16x8_eq, builtin_i16x8_eq); + +function builtin_i16x8_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.i16x8_ne, builtin_i16x8_ne); + +function builtin_i16x8_lt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i16x8_lt_s, builtin_i16x8_lt_s); + +function builtin_i16x8_lt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i16x8_lt_u, builtin_i16x8_lt_u); + +function builtin_i16x8_le_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i16x8_le_s, builtin_i16x8_le_s); + +function builtin_i16x8_le_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i16x8_le_u, builtin_i16x8_le_u); + +function builtin_i16x8_gt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i16x8_gt_s, builtin_i16x8_gt_s); + +function builtin_i16x8_gt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i16x8_gt_u, builtin_i16x8_gt_u); + +function builtin_i16x8_ge_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i16x8_ge_s, builtin_i16x8_ge_s); + +function builtin_i16x8_ge_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i16x8_ge_u, builtin_i16x8_ge_u); + +function builtin_i16x8_narrow_i32x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i16x8_narrow_i32x4_s, builtin_i16x8_narrow_i32x4_s); + +function builtin_i16x8_narrow_i32x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i16x8_narrow_i32x4_u, builtin_i16x8_narrow_i32x4_u); + +function builtin_i16x8_widen_low_i8x16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_low_i8x16_s, builtin_i16x8_widen_low_i8x16_s); + +function builtin_i16x8_widen_low_i8x16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_low_i8x16_u, builtin_i16x8_widen_low_i8x16_u); + +function builtin_i16x8_widen_high_i8x16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_high_i8x16_s, builtin_i16x8_widen_high_i8x16_s); + +function builtin_i16x8_widen_high_i8x16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_high_i8x16_u, builtin_i16x8_widen_high_i8x16_u); + +function builtin_i16x8_load8x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i16x8_load8x8_s, builtin_i16x8_load8x8_s); + +function builtin_i16x8_load8x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i16x8_load8x8_u, builtin_i16x8_load8x8_u); + +function builtin_i32x4_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i32x4_splat, builtin_i32x4_splat); + +function builtin_i32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i32x4_extract_lane, builtin_i32x4_extract_lane); + +function builtin_i32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i32x4_replace_lane, builtin_i32x4_replace_lane); + +function builtin_i32x4_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i32x4_add, builtin_i32x4_add); + +function builtin_i32x4_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i32x4_sub, builtin_i32x4_sub); + +function builtin_i32x4_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.i32x4_mul, builtin_i32x4_mul); + +function builtin_i32x4_min_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i32x4_min_s, builtin_i32x4_min_s); + +function builtin_i32x4_min_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i32x4_min_u, builtin_i32x4_min_u); + +function builtin_i32x4_max_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i32x4_max_s, builtin_i32x4_max_s); + +function builtin_i32x4_max_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i32x4_max_u, builtin_i32x4_max_u); + +function builtin_i32x4_dot_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_dot(ctx); +} +builtins.set(BuiltinNames.i32x4_dot_i16x8_s, builtin_i32x4_dot_i16x8_s); + +function builtin_i32x4_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i32x4_neg, builtin_i32x4_neg); + +function builtin_i32x4_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i32x4_shl, builtin_i32x4_shl); + +function builtin_i32x4_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i32x4_shr_s, builtin_i32x4_shr_s); + +function builtin_i32x4_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i32x4_shr_u, builtin_i32x4_shr_u); + +function builtin_i32x4_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i32x4_any_true, builtin_i32x4_any_true); + +function builtin_i32x4_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i32x4_all_true, builtin_i32x4_all_true); + +function builtin_i32x4_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.i32x4_eq, builtin_i32x4_eq); + +function builtin_i32x4_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.i32x4_ne, builtin_i32x4_ne); + +function builtin_i32x4_lt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i32x4_lt_s, builtin_i32x4_lt_s); + +function builtin_i32x4_lt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i32x4_lt_u, builtin_i32x4_lt_u); + +function builtin_i32x4_le_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i32x4_le_s, builtin_i32x4_le_s); + +function builtin_i32x4_le_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i32x4_le_u, builtin_i32x4_le_u); + +function builtin_i32x4_gt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i32x4_gt_s, builtin_i32x4_gt_s); + +function builtin_i32x4_gt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i32x4_gt_u, builtin_i32x4_gt_u); + +function builtin_i32x4_ge_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i32x4_ge_s, builtin_i32x4_ge_s); + +function builtin_i32x4_ge_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i32x4_ge_u, builtin_i32x4_ge_u); + +function builtin_i32x4_trunc_sat_f32x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i32x4_trunc_sat_f32x4_s, builtin_i32x4_trunc_sat_f32x4_s); + +function builtin_i32x4_trunc_sat_f32x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i32x4_trunc_sat_f32x4_u, builtin_i32x4_trunc_sat_f32x4_u); + +function builtin_i32x4_widen_low_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_low_i16x8_s, builtin_i32x4_widen_low_i16x8_s); + +function builtin_i32x4_widen_low_i16x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_low_i16x8_u, builtin_i32x4_widen_low_i16x8_u); + +function builtin_i32x4_widen_high_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_high_i16x8_s, builtin_i32x4_widen_high_i16x8_s); + +function builtin_i32x4_widen_high_i16x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_high_i16x8_u, builtin_i32x4_widen_high_i16x8_u); + +function builtin_i32x4_load16x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i32x4_load16x4_s, builtin_i32x4_load16x4_s); + +function builtin_i32x4_load16x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i32x4_load16x4_u, builtin_i32x4_load16x4_u); + +function builtin_i64x2_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i64x2_splat, builtin_i64x2_splat); + +function builtin_i64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i64x2_extract_lane, builtin_i64x2_extract_lane); + +function builtin_i64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i64x2_replace_lane, builtin_i64x2_replace_lane); + +function builtin_i64x2_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i64x2_add, builtin_i64x2_add); + +function builtin_i64x2_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i64x2_sub, builtin_i64x2_sub); + +function builtin_i64x2_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i64x2_neg, builtin_i64x2_neg); + +function builtin_i64x2_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i64x2_shl, builtin_i64x2_shl); + +function builtin_i64x2_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i64x2_shr_s, builtin_i64x2_shr_s); + +function builtin_i64x2_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i64x2_shr_u, builtin_i64x2_shr_u); + +function builtin_i64x2_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i64x2_any_true, builtin_i64x2_any_true); + +function builtin_i64x2_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i64x2_all_true, builtin_i64x2_all_true); + +function builtin_i64x2_trunc_sat_f64x2_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i64x2_trunc_sat_f64x2_s, builtin_i64x2_trunc_sat_f64x2_s); + +function builtin_i64x2_trunc_sat_f64x2_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i64x2_trunc_sat_f64x2_u, builtin_i64x2_trunc_sat_f64x2_u); + +function builtin_i64x2_load32x2_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i64x2_load32x2_s, builtin_i64x2_load32x2_s); + +function builtin_i64x2_load32x2_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i64x2_load32x2_u, builtin_i64x2_load32x2_u); + +function builtin_f32x4_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.f32x4_splat, builtin_f32x4_splat); + +function builtin_f32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.f32x4_extract_lane, builtin_f32x4_extract_lane); + +function builtin_f32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.f32x4_replace_lane, builtin_f32x4_replace_lane); + +function builtin_f32x4_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.f32x4_add, builtin_f32x4_add); + +function builtin_f32x4_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.f32x4_sub, builtin_f32x4_sub); + +function builtin_f32x4_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.f32x4_mul, builtin_f32x4_mul); + +function builtin_f32x4_div(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_div(ctx); +} +builtins.set(BuiltinNames.f32x4_div, builtin_f32x4_div); + +function builtin_f32x4_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.f32x4_neg, builtin_f32x4_neg); + +function builtin_f32x4_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.f32x4_min, builtin_f32x4_min); + +function builtin_f32x4_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.f32x4_max, builtin_f32x4_max); + +function builtin_f32x4_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_abs(ctx); +} +builtins.set(BuiltinNames.f32x4_abs, builtin_f32x4_abs); + +function builtin_f32x4_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sqrt(ctx); +} +builtins.set(BuiltinNames.f32x4_sqrt, builtin_f32x4_sqrt); + +function builtin_f32x4_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.f32x4_eq, builtin_f32x4_eq); + +function builtin_f32x4_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.f32x4_ne, builtin_f32x4_ne); + +function builtin_f32x4_lt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.f32x4_lt, builtin_f32x4_lt); + +function builtin_f32x4_le(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.f32x4_le, builtin_f32x4_le); + +function builtin_f32x4_gt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.f32x4_gt, builtin_f32x4_gt); + +function builtin_f32x4_ge(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.f32x4_ge, builtin_f32x4_ge); + +function builtin_f32x4_convert_i32x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f32x4_convert_i32x4_s, builtin_f32x4_convert_i32x4_s); + +function builtin_f32x4_convert_i32x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f32x4_convert_i32x4_u, builtin_f32x4_convert_i32x4_u); + +function builtin_f32x4_qfma(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfma(ctx); +} +builtins.set(BuiltinNames.f32x4_qfma, builtin_f32x4_qfma); + +function builtin_f32x4_qfms(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfms(ctx); +} +builtins.set(BuiltinNames.f32x4_qfms, builtin_f32x4_qfms); + +function builtin_f64x2_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.f64x2_splat, builtin_f64x2_splat); + +function builtin_f64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.f64x2_extract_lane, builtin_f64x2_extract_lane); + +function builtin_f64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.f64x2_replace_lane, builtin_f64x2_replace_lane); + +function builtin_f64x2_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.f64x2_add, builtin_f64x2_add); + +function builtin_f64x2_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.f64x2_sub, builtin_f64x2_sub); + +function builtin_f64x2_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.f64x2_mul, builtin_f64x2_mul); + +function builtin_f64x2_div(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_div(ctx); +} +builtins.set(BuiltinNames.f64x2_div, builtin_f64x2_div); + +function builtin_f64x2_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.f64x2_neg, builtin_f64x2_neg); + +function builtin_f64x2_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.f64x2_min, builtin_f64x2_min); + +function builtin_f64x2_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.f64x2_max, builtin_f64x2_max); + +function builtin_f64x2_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_abs(ctx); +} +builtins.set(BuiltinNames.f64x2_abs, builtin_f64x2_abs); + +function builtin_f64x2_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sqrt(ctx); +} +builtins.set(BuiltinNames.f64x2_sqrt, builtin_f64x2_sqrt); + +function builtin_f64x2_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.f64x2_eq, builtin_f64x2_eq); + +function builtin_f64x2_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.f64x2_ne, builtin_f64x2_ne); + +function builtin_f64x2_lt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.f64x2_lt, builtin_f64x2_lt); + +function builtin_f64x2_le(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.f64x2_le, builtin_f64x2_le); + +function builtin_f64x2_gt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.f64x2_gt, builtin_f64x2_gt); + +function builtin_f64x2_ge(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.f64x2_ge, builtin_f64x2_ge); + +function builtin_f64x2_convert_i64x2_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f64x2_convert_i64x2_s, builtin_f64x2_convert_i64x2_s); + +function builtin_f64x2_convert_i64x2_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f64x2_convert_i64x2_u, builtin_f64x2_convert_i64x2_u); + +function builtin_f64x2_qfma(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfma(ctx); +} +builtins.set(BuiltinNames.f64x2_qfma, builtin_f64x2_qfma); + +function builtin_f64x2_qfms(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfms(ctx); +} +builtins.set(BuiltinNames.f64x2_qfms, builtin_f64x2_qfms); + +function builtin_v8x16_shuffle(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shuffle(ctx); +} +builtins.set(BuiltinNames.v8x16_shuffle, builtin_v8x16_shuffle); + +function builtin_v8x16_swizzle(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = null; + ctx.contextualType = Type.v128; + return builtin_v128_swizzle(ctx); +} +builtins.set(BuiltinNames.v8x16_swizzle, builtin_v8x16_swizzle); + +function builtin_v8x16_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v8x16_load_splat, builtin_v8x16_load_splat); + +function builtin_v16x8_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v16x8_load_splat, builtin_v16x8_load_splat); + +function builtin_v32x4_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v32x4_load_splat, builtin_v32x4_load_splat); + +function builtin_v64x2_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v64x2_load_splat, builtin_v64x2_load_splat); + +// === Internal helpers ======================================================================= /** Compiles the `visit_globals` function. */ export function compileVisitGlobals(compiler: Compiler): void { @@ -5409,7 +7842,7 @@ function evaluateConstantType(ctx: BuiltinContext): Type | null { return typeArguments[0]; } if (operands.length == 1) { // optional type argument - if (typeArguments !== null && typeArguments.length) { + if (typeArguments !== null && typeArguments.length > 0) { if (typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, @@ -5423,7 +7856,7 @@ function evaluateConstantType(ctx: BuiltinContext): Type | null { } return compiler.currentType; } - if (typeArguments && typeArguments.length > 1) { + if (typeArguments !== null && typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, ctx.reportNode.typeArgumentsRange, "1", typeArguments.length.toString() diff --git a/src/compiler.ts b/src/compiler.ts index 2b0dd1cfe5..bc94f06922 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5,7 +5,8 @@ import { BuiltinNames, - compileCall as compileBuiltinCall, + BuiltinContext, + builtins, compileVisitGlobals, compileVisitMembers, compileRTTI, @@ -6382,16 +6383,24 @@ export class Compiler extends DiagnosticEmitter { expression ); } - - // now compile the builtin, which usually returns a block of code that replaces the call. - return compileBuiltinCall( - this, - prototype, - typeArguments, - expression.arguments, - contextualType, - expression + var ctx = new BuiltinContext(); + ctx.compiler = this; + ctx.prototype = prototype; + ctx.typeArguments = typeArguments; + ctx.operands = expression.arguments; + ctx.contextualType = contextualType; + ctx.reportNode = expression; + ctx.contextIsExact = false; + var internalName = prototype.internalName; + if (builtins.has(internalName)) { + let fn = builtins.get(internalName)!; + return fn(ctx); + } + this.error( + DiagnosticCode.Not_implemented, + expression.expression.range ); + return this.module.unreachable(); } /** diff --git a/src/diagnostics.ts b/src/diagnostics.ts index 2cf3927cde..82f3d32b4e 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -269,16 +269,16 @@ export abstract class DiagnosticEmitter { if (range) { let seen = this.seen; if (seen.has(range.source)) { - let seenInSource = seen.get(range.source)!; + let seenInSource = assert(seen.get(range.source)); if (seenInSource.has(range.start)) { - let seenCodesAtPos = seenInSource.get(range.start)!; + let seenCodesAtPos = assert(seenInSource.get(range.start)); if (seenCodesAtPos.includes(code)) return; seenCodesAtPos.push(code); } else { seenInSource.set(range.start, [ code ]); } } else { - let seenInSource = new Map(); + let seenInSource = new Map(); seenInSource.set(range.start, [ code ]); seen.set(range.source, seenInSource); } diff --git a/src/flow.ts b/src/flow.ts index 98c60cf888..c6a8d22c52 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -228,7 +228,9 @@ export class Flow { /** Gets the actual function being compiled, The inlined function when inlining, otherwise the parent function. */ get actualFunction(): Function { - return this.inlineFunction || this.parentFunction; + var inlineFunction = this.inlineFunction; + if (inlineFunction) return inlineFunction; + return this.parentFunction; } /** Tests if this flow has the specified flag or flags. */ diff --git a/src/program.ts b/src/program.ts index 8f1731257c..2230a28ab4 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1629,7 +1629,7 @@ export class Program extends DiagnosticEmitter { let queued: QueuedExportStar[]; if (queuedExportsStar.has(parent)) queued = queuedExportsStar.get(parent)!; else queuedExportsStar.set(parent, queued = []); - let foreignPath = assert(statement.internalPath); // must be set for export * + let foreignPath = statement.internalPath!; // must be set for export * queued.push(new QueuedExportStar( foreignPath, foreignPath.endsWith(INDEX_SUFFIX) // strip or add index depending on what's already present @@ -2186,7 +2186,7 @@ export abstract class Element { /** Looks up the element with the specified name within this element. */ lookupInSelf(name: string): DeclaredElement | null { var members = this.members; - if (members && members.has(name)) return members.get(name)!; + if (members !== null && members.has(name)) return members.get(name)!; return null; } @@ -2199,7 +2199,7 @@ export abstract class Element { var members = this.members; if (!members) this.members = members = new Map(); else if (members.has(name)) { - let existing = members.get(name)!; + let existing = assert(members.get(name)); if (existing.parent !== this) { // override non-own element } else { @@ -2807,7 +2807,7 @@ export class FunctionPrototype extends DeclaredElement { assert(!this.isBound); var boundPrototypes = this.boundPrototypes; if (!boundPrototypes) this.boundPrototypes = boundPrototypes = new Map(); - else if (boundPrototypes.has(classInstance)) return boundPrototypes.get(classInstance)!; + else if (boundPrototypes.has(classInstance)) return assert(boundPrototypes.get(classInstance)); var declaration = this.declaration; assert(declaration.kind == NodeKind.METHODDECLARATION); var bound = new FunctionPrototype( this.name, @@ -2825,7 +2825,7 @@ export class FunctionPrototype extends DeclaredElement { /** Gets the resolved instance for the specified instance key, if already resolved. */ getResolvedInstance(instanceKey: string): Function | null { var instances = this.instances; - if (instances && instances.has(instanceKey)) return instances.get(instanceKey); + if (instances !== null && instances.has(instanceKey)) return instances.get(instanceKey); return null; } @@ -3335,7 +3335,7 @@ export class ClassPrototype extends DeclaredElement { /** Gets the resolved instance for the specified instance key, if already resolved. */ getResolvedInstance(instanceKey: string): Class | null { var instances = this.instances; - if (instances && instances.has(instanceKey)) return instances.get(instanceKey); + if (instances !== null && instances.has(instanceKey)) return instances.get(instanceKey); return null; } @@ -3457,7 +3457,7 @@ export class Class extends TypedElement { this.contextualTypeArguments.set(typeParameters[i].name.text, typeArguments[i]); } } - } else if (typeParameters && typeParameters.length) { + } else if (typeParameters !== null && typeParameters.length > 0) { throw new Error("type argument count mismatch"); } registerConcreteElement(program, this); @@ -3475,7 +3475,7 @@ export class Class extends TypedElement { // for (let [baseName, baseType] of inheritedTypeArguments) { for (let _keys = Map_keys(inheritedTypeArguments), i = 0, k = _keys.length; i < k; ++i) { let baseName = unchecked(_keys[i]); - let baseType = inheritedTypeArguments.get(baseName)!; + let baseType = assert(inheritedTypeArguments.get(baseName)); if (!contextualTypeArguments) { this.contextualTypeArguments = contextualTypeArguments = new Map(); contextualTypeArguments.set(baseName, baseType); @@ -3598,21 +3598,22 @@ export class Class extends TypedElement { while (current.base !== abvInstance) { current = assert(current.base); } - switch (current.prototype) { - case program.i8ArrayPrototype: return Type.i8; - case program.i16ArrayPrototype: return Type.i16; - case program.i32ArrayPrototype: return Type.i32; - case program.i64ArrayPrototype: return Type.i64; - case program.u8ArrayPrototype: - case program.u8ClampedArrayPrototype: return Type.u8; - case program.u16ArrayPrototype: return Type.u16; - case program.u32ArrayPrototype: return Type.u32; - case program.u64ArrayPrototype: return Type.u64; - case program.f32ArrayPrototype: return Type.f32; - case program.f64ArrayPrototype: return Type.f64; - case program.arrayPrototype: return assert(this.getTypeArgumentsTo(program.arrayPrototype))[0]; - default: assert(false); - } + var prototype = current.prototype; + if (prototype == program.arrayPrototype) { + return assert(this.getTypeArgumentsTo(program.arrayPrototype))[0]; + } + if (prototype == program.i8ArrayPrototype) return Type.i8; + if (prototype == program.i16ArrayPrototype) return Type.i16; + if (prototype == program.i32ArrayPrototype) return Type.i32; + if (prototype == program.i64ArrayPrototype) return Type.i64; + if (prototype == program.u8ArrayPrototype) return Type.u8; + if (prototype == program.u8ClampedArrayPrototype) return Type.u8; + if (prototype == program.u16ArrayPrototype) return Type.u16; + if (prototype == program.u32ArrayPrototype) return Type.u32; + if (prototype == program.u64ArrayPrototype) return Type.u64; + if (prototype == program.f32ArrayPrototype) return Type.f32; + if (prototype == program.f64ArrayPrototype) return Type.f64; + assert(false); return Type.void; } @@ -3863,7 +3864,7 @@ function copyMembers(src: Element, dest: Element): void { // for (let [memberName, member] of srcMembers) { for (let _keys = Map_keys(srcMembers), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); - let member = srcMembers.get(memberName)!; + let member = assert(srcMembers.get(memberName)); destMembers.set(memberName, member); } } diff --git a/src/resolver.ts b/src/resolver.ts index e993117718..bc0a594f18 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -181,8 +181,8 @@ export class Resolver extends DiagnosticEmitter { if (isSimpleType) { let simpleName = nameNode.identifier.text; if (ctxTypes !== null && ctxTypes.has(simpleName)) { - let type = ctxTypes.get(simpleName)!; - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + let type = assert(ctxTypes.get(simpleName)); + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -208,14 +208,15 @@ export class Resolver extends DiagnosticEmitter { if (!element) return null; // Use shadow type if present (i.e. namespace sharing a type) - if (element.shadowType) { - element = element.shadowType; + var shadowType = element.shadowType; + if (shadowType) { + element = shadowType; } else { // Handle enums (become i32) if (element.kind == ElementKind.ENUM) { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -604,7 +605,7 @@ export class Resolver extends DiagnosticEmitter { /** Contextual element. */ ctxElement: Element, /** How to proceed with eventual diagnostics. */ - reportMode = ReportMode.REPORT + reportMode: ReportMode = ReportMode.REPORT ): Element | null { var element = ctxElement.lookup(node.identifier.text); if (!element) { @@ -661,8 +662,8 @@ export class Resolver extends DiagnosticEmitter { DiagnosticCode.Expected_0_type_arguments_but_got_1, argumentCount ? Range.join( - (typeArgumentNodes)[0].range, - (typeArgumentNodes)[argumentCount - 1].range + typeArgumentNodes![0].range, + typeArgumentNodes![argumentCount - 1].range ) : assert(alternativeReportNode).range, (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(), @@ -674,7 +675,7 @@ export class Resolver extends DiagnosticEmitter { for (let i = 0; i < maxParameterCount; ++i) { let type = i < argumentCount ? this.resolveType( // reports - (typeArgumentNodes)[i], + typeArgumentNodes![i], ctxElement, ctxTypes, reportMode @@ -2639,8 +2640,8 @@ export class Resolver extends DiagnosticEmitter { var signatureNode = prototype.functionTypeNode; var typeParameterNodes = prototype.typeParameterNodes; var numFunctionTypeArguments: i32; - if (typeArguments && (numFunctionTypeArguments = typeArguments.length)) { - assert(typeParameterNodes && numFunctionTypeArguments == typeParameterNodes.length); + if (typeArguments !== null && (numFunctionTypeArguments = typeArguments.length) > 0) { + assert(typeParameterNodes !== null && numFunctionTypeArguments == typeParameterNodes.length); for (let i = 0; i < numFunctionTypeArguments; ++i) { ctxTypes.set( (typeParameterNodes)[i].name.text, @@ -2856,7 +2857,7 @@ export class Resolver extends DiagnosticEmitter { } } else { let typeParameterNodes = prototype.typeParameterNodes; - assert(!(typeParameterNodes && typeParameterNodes.length)); + assert(!(typeParameterNodes !== null && typeParameterNodes.length > 0)); } instance.contextualTypeArguments = ctxTypes; @@ -2942,8 +2943,8 @@ export class Resolver extends DiagnosticEmitter { if (!fieldTypeNode) { if (base) { let baseMembers = base.members; - if (baseMembers && baseMembers.has((member).name)) { - let baseField = baseMembers.get((member).name)!; + if (baseMembers !== null && baseMembers.has((member).name)) { + let baseField = assert(baseMembers.get((member).name)); if (!baseField.is(CommonFlags.PRIVATE)) { assert(baseField.kind == ElementKind.FIELD); fieldType = (baseField).type; @@ -3155,7 +3156,7 @@ export class Resolver extends DiagnosticEmitter { // Otherwise make sure that no type arguments have been specified } else { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, diff --git a/src/types.ts b/src/types.ts index ef89d9e4c3..3bc5dab466 100644 --- a/src/types.ts +++ b/src/types.ts @@ -214,14 +214,15 @@ export class Type { /** Composes the respective nullable type of this type. */ asNullable(): Type { assert(this.is(TypeFlags.REFERENCE)); - if (!this.cachedNullableType) { + var cachedNullableType = this.cachedNullableType; + if (!cachedNullableType) { assert(!this.is(TypeFlags.NULLABLE)); - this.cachedNullableType = new Type(this.kind, this.flags | TypeFlags.NULLABLE, this.size); - this.cachedNullableType.nonNullableType = this; - this.cachedNullableType.classReference = this.classReference; // either a class reference - this.cachedNullableType.signatureReference = this.signatureReference; // or a function reference + this.cachedNullableType = cachedNullableType = new Type(this.kind, this.flags | TypeFlags.NULLABLE, this.size); + cachedNullableType.nonNullableType = this; + cachedNullableType.classReference = this.classReference; // either a class reference + cachedNullableType.signatureReference = this.signatureReference; // or a function reference } - return this.cachedNullableType; + return cachedNullableType; } /** Tests if a value of this type is assignable to the target type incl. implicit conversion. */ diff --git a/src/util/collections.ts b/src/util/collections.ts index 972e199299..fb107d7e6c 100644 --- a/src/util/collections.ts +++ b/src/util/collections.ts @@ -27,7 +27,7 @@ export function makeMap(original: Map | null = null, overrides: Map(original: Map | null = null, overrides: Map(isTrueish: T | null, message?: string): T; +declare function assert(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; /** Parses a floating point string to a 64-bit float. */ From 9ea312a57048d8efa3dce07a55c2621283bad836 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 29 Feb 2020 09:15:52 +0100 Subject: [PATCH 09/28] refactor hell part 3, down to 197 --- src/ast.ts | 10 +- src/builtins.ts | 148 +++++++++++------- src/compiler.ts | 2 +- src/definitions.ts | 10 +- src/diagnostics.ts | 19 +-- src/flow.ts | 37 +++-- src/glue/wasm/float.ts | 4 + src/glue/wasm/i64.ts | 54 +++++-- src/glue/wasm/mapset.ts | 3 + src/module.ts | 36 ++++- src/parser.ts | 38 +++-- src/program.ts | 105 +++++++------ src/resolver.ts | 18 +-- std/assembly/index.d.ts | 2 +- std/assembly/string.ts | 11 ++ std/portable/index.d.ts | 2 +- .../std/string-encoding.optimized.wat | 4 +- .../std/string-encoding.untouched.wat | 4 +- tests/compiler/std/string.optimized.wat | 4 +- tests/compiler/std/string.untouched.wat | 4 +- 20 files changed, 329 insertions(+), 186 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index 9e0bfb67ec..44e207f34f 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -1324,10 +1324,8 @@ export namespace DecoratorKind { break; } case CharCode.p: { - switch (propStr) { - case "prefix": return DecoratorKind.OPERATOR_PREFIX; - case "postfix": return DecoratorKind.OPERATOR_POSTFIX; - } + if (propStr == "prefix") return DecoratorKind.OPERATOR_PREFIX; + if (propStr == "postfix") return DecoratorKind.OPERATOR_POSTFIX; break; } } @@ -1534,7 +1532,7 @@ export class NewExpression extends Expression { get typeArgumentsRange(): Range { var typeArguments = this.typeArguments; var numTypeArguments: i32; - if (typeArguments && (numTypeArguments = typeArguments.length)) { + if (typeArguments !== null && (numTypeArguments = typeArguments.length) > 0) { return Range.join(typeArguments[0].range, typeArguments[numTypeArguments - 1].range); } return this.typeName.range; @@ -1789,7 +1787,7 @@ export class EnumValueDeclaration extends VariableLikeDeclarationStatement { } /** Represents an `export import` statement of an interface. */ -export class ExportImportStatement extends Node { +export class ExportImportStatement extends Statement { /** Identifier being imported. */ name: IdentifierExpression; /** Identifier being exported. */ diff --git a/src/builtins.ts b/src/builtins.ts index b60a768f6c..efc43abd08 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -598,9 +598,7 @@ function builtin_isInteger(ctx: BuiltinContext): ExpressionRef { var type = evaluateConstantType(ctx); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) - ? module.i32(1) - : module.i32(0); + return module.i32(type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) ? 1 : 0); } builtins.set(BuiltinNames.isInteger, builtin_isInteger); @@ -611,9 +609,7 @@ function builtin_isFloat(ctx: BuiltinContext): ExpressionRef { var type = evaluateConstantType(ctx); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - return type.is(TypeFlags.FLOAT) - ? module.i32(1) - : module.i32(0); + return module.i32(type.is(TypeFlags.FLOAT) ? 1 : 0); } builtins.set(BuiltinNames.isFloat, builtin_isFloat); @@ -624,9 +620,7 @@ function builtin_isBoolean(ctx: BuiltinContext): ExpressionRef { var type = evaluateConstantType(ctx); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - return type == Type.bool - ? module.i32(1) - : module.i32(0); + return module.i32(type == Type.bool ? 1 : 0); } builtins.set(BuiltinNames.isBoolean, builtin_isBoolean); @@ -637,7 +631,7 @@ function builtin_isSigned(ctx: BuiltinContext): ExpressionRef { var type = evaluateConstantType(ctx); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - return module.i32(i32(type.is(TypeFlags.SIGNED))); + return module.i32(type.is(TypeFlags.SIGNED) ? 1 : 0); } builtins.set(BuiltinNames.isSigned, builtin_isSigned); @@ -648,9 +642,7 @@ function builtin_isReference(ctx: BuiltinContext): ExpressionRef { var type = evaluateConstantType(ctx); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - return type.is(TypeFlags.REFERENCE) - ? module.i32(1) - : module.i32(0); + return module.i32(type.is(TypeFlags.REFERENCE) ? 1 : 0); } builtins.set(BuiltinNames.isReference, builtin_isReference); @@ -665,7 +657,7 @@ function builtin_isString(ctx: BuiltinContext): ExpressionRef { let classReference = type.classReference; if (classReference) { let stringInstance = compiler.program.stringInstance; - if (stringInstance && classReference.isAssignableTo(stringInstance)) return module.i32(1); + if (stringInstance !== null && classReference.isAssignableTo(stringInstance)) return module.i32(1); } } return module.i32(0); @@ -876,7 +868,6 @@ function builtin_offsetof(ctx: BuiltinContext): ExpressionRef { } return module.unreachable(); } - var offset: i32; if (operands.length) { if ( operands[0].kind != NodeKind.LITERAL || @@ -889,19 +880,20 @@ function builtin_offsetof(ctx: BuiltinContext): ExpressionRef { return module.unreachable(); } let fieldName = (operands[0]).value; - let field = classType.members ? classType.members.get(fieldName) : null; - if (!(field && field.kind == ElementKind.FIELD)) { - compiler.error( - DiagnosticCode.Type_0_has_no_property_1, - operands[0].range, classType.internalName, fieldName - ); - return module.unreachable(); + let classMembers = classType.members; + if (classMembers !== null && classMembers.has(fieldName)) { + let member = assert(classMembers.get(fieldName)); + if (member.kind == ElementKind.FIELD) { + return contextualUsize(compiler, i64_new((member).memoryOffset), contextualType); + } } - offset = (field).memoryOffset; - } else { - offset = classType.nextMemoryOffset; + compiler.error( + DiagnosticCode.Type_0_has_no_property_1, + operands[0].range, classType.internalName, fieldName + ); + return module.unreachable(); } - return contextualUsize(compiler, i64_new(offset), contextualType); + return contextualUsize(compiler, i64_new(classType.nextMemoryOffset), contextualType); } builtins.set(BuiltinNames.offsetof, builtin_offsetof); @@ -3230,25 +3222,25 @@ function builtin_v128_extract_lane(ctx: BuiltinContext): ExpressionRef { idx = 0; } switch (type.kind) { - case TypeKind.I8: return module.simd_extract(SIMDExtractOp.ExtractLaneI8x16, arg0, idx); - case TypeKind.U8: return module.simd_extract(SIMDExtractOp.ExtractLaneU8x16, arg0, idx); - case TypeKind.I16: return module.simd_extract(SIMDExtractOp.ExtractLaneI16x8, arg0, idx); - case TypeKind.U16: return module.simd_extract(SIMDExtractOp.ExtractLaneU16x8, arg0, idx); + case TypeKind.I8: return module.simd_extract(SIMDExtractOp.ExtractLaneI8x16, arg0, idx); + case TypeKind.U8: return module.simd_extract(SIMDExtractOp.ExtractLaneU8x16, arg0, idx); + case TypeKind.I16: return module.simd_extract(SIMDExtractOp.ExtractLaneI16x8, arg0, idx); + case TypeKind.U16: return module.simd_extract(SIMDExtractOp.ExtractLaneU16x8, arg0, idx); case TypeKind.I32: - case TypeKind.U32: return module.simd_extract(SIMDExtractOp.ExtractLaneI32x4, arg0, idx); + case TypeKind.U32: return module.simd_extract(SIMDExtractOp.ExtractLaneI32x4, arg0, idx); case TypeKind.I64: - case TypeKind.U64: return module.simd_extract(SIMDExtractOp.ExtractLaneI64x2, arg0, idx); + case TypeKind.U64: return module.simd_extract(SIMDExtractOp.ExtractLaneI64x2, arg0, idx); case TypeKind.ISIZE: case TypeKind.USIZE: { return module.simd_extract( compiler.options.isWasm64 ? SIMDExtractOp.ExtractLaneI64x2 : SIMDExtractOp.ExtractLaneI32x4, - arg0, idx + arg0, idx ); } - case TypeKind.F32: return module.simd_extract(SIMDExtractOp.ExtractLaneF32x4, arg0, idx); - case TypeKind.F64: return module.simd_extract(SIMDExtractOp.ExtractLaneF64x2, arg0, idx); + case TypeKind.F32: return module.simd_extract(SIMDExtractOp.ExtractLaneF32x4, arg0, idx); + case TypeKind.F64: return module.simd_extract(SIMDExtractOp.ExtractLaneF64x2, arg0, idx); } } compiler.error( @@ -3299,24 +3291,24 @@ function builtin_v128_replace_lane(ctx: BuiltinContext): ExpressionRef { } switch (type.kind) { case TypeKind.I8: - case TypeKind.U8: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI8x16, arg0, idx, arg2); + case TypeKind.U8: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI8x16, arg0, idx, arg2); case TypeKind.I16: - case TypeKind.U16: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI16x8, arg0, idx, arg2); + case TypeKind.U16: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI16x8, arg0, idx, arg2); case TypeKind.I32: - case TypeKind.U32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI32x4, arg0, idx, arg2); + case TypeKind.U32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI32x4, arg0, idx, arg2); case TypeKind.I64: - case TypeKind.U64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI64x2, arg0, idx, arg2); + case TypeKind.U64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI64x2, arg0, idx, arg2); case TypeKind.ISIZE: case TypeKind.USIZE: { return module.simd_replace( compiler.options.isWasm64 ? SIMDReplaceOp.ReplaceLaneI64x2 : SIMDReplaceOp.ReplaceLaneI32x4, - arg0, idx, arg2 + arg0, idx, arg2 ); } - case TypeKind.F32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF32x4, arg0, idx, arg2); - case TypeKind.F64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF64x2, arg0, idx, arg2); + case TypeKind.F32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF32x4, arg0, idx, arg2); + case TypeKind.F64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF64x2, arg0, idx, arg2); } } compiler.error( @@ -3797,7 +3789,7 @@ function builtin_v128_add_saturate(ctx: BuiltinContext): ExpressionRef { } var operands = ctx.operands; var typeArguments = ctx.typeArguments!; - var type = typeArguments![0]; + var type = typeArguments[0]; var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); if (!type.is(TypeFlags.REFERENCE)) { @@ -3830,7 +3822,7 @@ function builtin_v128_sub_saturate(ctx: BuiltinContext): ExpressionRef { } var operands = ctx.operands; var typeArguments = ctx.typeArguments!; - var type = typeArguments![0]; + var type = typeArguments[0]; var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); if (!type.is(TypeFlags.REFERENCE)) { @@ -4151,7 +4143,7 @@ function builtin_v128_le(ctx: BuiltinContext): ExpressionRef { } var operands = ctx.operands; var typeArguments = ctx.typeArguments!; - var type = typeArguments![0]; + var type = typeArguments[0]; var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); if (!type.is(TypeFlags.REFERENCE)) { @@ -4200,7 +4192,7 @@ function builtin_v128_gt(ctx: BuiltinContext): ExpressionRef { } var operands = ctx.operands; var typeArguments = ctx.typeArguments!; - var type = typeArguments![0]; + var type = typeArguments[0]; var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); if (!type.is(TypeFlags.REFERENCE)) { @@ -4249,7 +4241,7 @@ function builtin_v128_ge(ctx: BuiltinContext): ExpressionRef { } var operands = ctx.operands; var typeArguments = ctx.typeArguments!; - var type = typeArguments![0]; + var type = typeArguments[0]; var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); if (!type.is(TypeFlags.REFERENCE)) { @@ -6281,6 +6273,7 @@ function builtin_i8x16_shr_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_shr_u, builtin_i8x16_shr_u); +// i8x16.any_true -> v128.any_true function builtin_i8x16_any_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6289,6 +6282,7 @@ function builtin_i8x16_any_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_any_true, builtin_i8x16_any_true); +// i8x16.all_true -> v128.all_true function builtin_i8x16_all_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6297,6 +6291,7 @@ function builtin_i8x16_all_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_all_true, builtin_i8x16_all_true); +// i8x16.eq -> v128.eq function builtin_i8x16_eq(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6305,6 +6300,7 @@ function builtin_i8x16_eq(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_eq, builtin_i8x16_eq); +// i8x16.ne -> v128.ne function builtin_i8x16_ne(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6313,6 +6309,7 @@ function builtin_i8x16_ne(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_ne, builtin_i8x16_ne); +// i8x16.lt_s -> v128.lt function builtin_i8x16_lt_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6321,6 +6318,7 @@ function builtin_i8x16_lt_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_lt_s, builtin_i8x16_lt_s); +// i8x16.lt_u -> v128.lt function builtin_i8x16_lt_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6329,6 +6327,7 @@ function builtin_i8x16_lt_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_lt_u, builtin_i8x16_lt_u); +// i8x16.le_s -> v128.le function builtin_i8x16_le_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6337,6 +6336,7 @@ function builtin_i8x16_le_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_le_s, builtin_i8x16_le_s); +// i8x16.le_u -> v128.le function builtin_i8x16_le_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6345,6 +6345,7 @@ function builtin_i8x16_le_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_le_u, builtin_i8x16_le_u); +// i8x16.gt_s -> v128.gt function builtin_i8x16_gt_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6353,6 +6354,7 @@ function builtin_i8x16_gt_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_gt_s, builtin_i8x16_gt_s); +// i8x16.gt_u -> v128.gt function builtin_i8x16_gt_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6361,6 +6363,7 @@ function builtin_i8x16_gt_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_gt_u, builtin_i8x16_gt_u); +// i8x16.ge_s -> v128.ge function builtin_i8x16_ge_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6369,6 +6372,7 @@ function builtin_i8x16_ge_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_ge_s, builtin_i8x16_ge_s); +// i8x16.ge_u -> v128.ge function builtin_i8x16_ge_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6377,6 +6381,7 @@ function builtin_i8x16_ge_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_ge_u, builtin_i8x16_ge_u); +// i8x16.narrow_i16x8_s -> v128.narrow function builtin_i8x16_narrow_i16x8_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6385,6 +6390,7 @@ function builtin_i8x16_narrow_i16x8_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_narrow_i16x8_s, builtin_i8x16_narrow_i16x8_s); +// i8x16.narrow_i16x8_u -> v128.narrow function builtin_i8x16_narrow_i16x8_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6393,6 +6399,7 @@ function builtin_i8x16_narrow_i16x8_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i8x16_narrow_i16x8_u, builtin_i8x16_narrow_i16x8_u); +// i16x8.splat -> v128.splat function builtin_i16x8_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6401,22 +6408,25 @@ function builtin_i16x8_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_splat, builtin_i16x8_splat); +// i16x8.extract_lane_s -> v128.extract_lane function builtin_i16x8_extract_lane_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; - ctx.contextualType = Type.i16; + ctx.contextualType = Type.i32; return builtin_v128_extract_lane(ctx); } builtins.set(BuiltinNames.i16x8_extract_lane_s, builtin_i16x8_extract_lane_s); +// i16x8..extract_lane_u -> v128.extract_lane function builtin_i16x8_extract_lane_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; - ctx.contextualType = Type.u16; + ctx.contextualType = Type.i32; return builtin_v128_extract_lane(ctx); } builtins.set(BuiltinNames.i16x8_extract_lane_u, builtin_i16x8_extract_lane_u); +// i16x8.replace_lane -> v128.replace_lane function builtin_i16x8_replace_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6425,6 +6435,7 @@ function builtin_i16x8_replace_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_replace_lane, builtin_i16x8_replace_lane); +// i16x8.add -> v128.add function builtin_i16x8_add(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6433,6 +6444,7 @@ function builtin_i16x8_add(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_add, builtin_i16x8_add); +// i16x8.sub -> v128.sub function builtin_i16x8_sub(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6441,6 +6453,7 @@ function builtin_i16x8_sub(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_sub, builtin_i16x8_sub); +// i16x8.mul -> v128.mul function builtin_i16x8_mul(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6449,6 +6462,7 @@ function builtin_i16x8_mul(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_mul, builtin_i16x8_mul); +// i16x8.min_s -> v128.min function builtin_i16x8_min_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6457,6 +6471,7 @@ function builtin_i16x8_min_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_min_s, builtin_i16x8_min_s); +// i16x8.min_u -> v128.min function builtin_i16x8_min_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6465,6 +6480,7 @@ function builtin_i16x8_min_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_min_u, builtin_i16x8_min_u); +// i16x8.max_s -> v128.max function builtin_i16x8_max_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6473,6 +6489,7 @@ function builtin_i16x8_max_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_max_s, builtin_i16x8_max_s); +// i16x8.max_u -> v128.max function builtin_i16x8_max_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6481,6 +6498,7 @@ function builtin_i16x8_max_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_max_u, builtin_i16x8_max_u); +// i16x8.avgr_u -> v128.avgr function builtin_i16x8_avgr_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6489,6 +6507,7 @@ function builtin_i16x8_avgr_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_avgr_u, builtin_i16x8_avgr_u); +// i16x8.neg -> v128.neg function builtin_i16x8_neg(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6497,6 +6516,7 @@ function builtin_i16x8_neg(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_neg, builtin_i16x8_neg); +// i16x8.add_saturate_s -> v128.add_saturate function builtin_i16x8_add_saturate_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6505,6 +6525,7 @@ function builtin_i16x8_add_saturate_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_add_saturate_s, builtin_i16x8_add_saturate_s); +// i16x8.add_saturate_u -> v128.add_saturate function builtin_i16x8_add_saturate_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6513,6 +6534,7 @@ function builtin_i16x8_add_saturate_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_add_saturate_u, builtin_i16x8_add_saturate_u); +// i16x8.sub_saturate_s -> v128.sub_saturate function builtin_i16x8_sub_saturate_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6521,6 +6543,7 @@ function builtin_i16x8_sub_saturate_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_sub_saturate_s, builtin_i16x8_sub_saturate_s); +// i16x8.sub_saturate_u -> v128.sub_saturate function builtin_i16x8_sub_saturate_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6529,6 +6552,7 @@ function builtin_i16x8_sub_saturate_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_sub_saturate_u, builtin_i16x8_sub_saturate_u); +// i16x8.shl -> v128.shl function builtin_i16x8_shl(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6537,6 +6561,7 @@ function builtin_i16x8_shl(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_shl, builtin_i16x8_shl); +// i16x8.shr_s -> v128.shr function builtin_i16x8_shr_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6545,6 +6570,7 @@ function builtin_i16x8_shr_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_shr_s, builtin_i16x8_shr_s); +// i16x8.shr_u -> v128.shr function builtin_i16x8_shr_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6553,6 +6579,7 @@ function builtin_i16x8_shr_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_shr_u, builtin_i16x8_shr_u); +// i16x8.any_true -> v128.any_true function builtin_i16x8_any_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6561,6 +6588,7 @@ function builtin_i16x8_any_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_any_true, builtin_i16x8_any_true); +// i16x8.all_true -> v128.all_true function builtin_i16x8_all_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6569,6 +6597,7 @@ function builtin_i16x8_all_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_all_true, builtin_i16x8_all_true); +// i16x8.eq -> v128.eq function builtin_i16x8_eq(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6577,6 +6606,7 @@ function builtin_i16x8_eq(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_eq, builtin_i16x8_eq); +// i16x8.ne -> v128.ne function builtin_i16x8_ne(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6585,6 +6615,7 @@ function builtin_i16x8_ne(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_ne, builtin_i16x8_ne); +// i16x8.lt_s -> v128.lt function builtin_i16x8_lt_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6593,6 +6624,7 @@ function builtin_i16x8_lt_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_lt_s, builtin_i16x8_lt_s); +// i16x8.lt_u -> v128.lt function builtin_i16x8_lt_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6601,6 +6633,7 @@ function builtin_i16x8_lt_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_lt_u, builtin_i16x8_lt_u); +// i16x8.le_s -> v128.le function builtin_i16x8_le_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6609,6 +6642,7 @@ function builtin_i16x8_le_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_le_s, builtin_i16x8_le_s); +// i16x8.le_u -> v128.le function builtin_i16x8_le_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6617,6 +6651,7 @@ function builtin_i16x8_le_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_le_u, builtin_i16x8_le_u); +// i16x8.gt_s -> v128.gt function builtin_i16x8_gt_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6625,6 +6660,7 @@ function builtin_i16x8_gt_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_gt_s, builtin_i16x8_gt_s); +// i16x8.gt_u -> v128.gt function builtin_i16x8_gt_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6633,6 +6669,7 @@ function builtin_i16x8_gt_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_gt_u, builtin_i16x8_gt_u); +// i16x8.ge_s -> v128.ge function builtin_i16x8_ge_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6641,6 +6678,7 @@ function builtin_i16x8_ge_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_ge_s, builtin_i16x8_ge_s); +// i16x8.ge_u -> v128.ge function builtin_i16x8_ge_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -6649,6 +6687,7 @@ function builtin_i16x8_ge_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_ge_u, builtin_i16x8_ge_u); +// i16x8.narrow_i32x4_s -> v128.narrow function builtin_i16x8_narrow_i32x4_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6657,6 +6696,7 @@ function builtin_i16x8_narrow_i32x4_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_narrow_i32x4_s, builtin_i16x8_narrow_i32x4_s); +// i16x8.narrow_i32x4_u -> v128.narrow function builtin_i16x8_narrow_i32x4_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -7610,7 +7650,7 @@ export function compileVisitMembers(compiler: Compiler): void { // for (let [instanceId, instance] of managedClasses) { for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { let instanceId = _keys[i]; - let instance = managedClasses.get(instanceId)!; + let instance = assert(managedClasses.get(instanceId)); assert(instance.type.isManaged); assert(instanceId == lastId++); @@ -7618,7 +7658,7 @@ export function compileVisitMembers(compiler: Compiler): void { let code = new Array(); // if a library element, check if it implements a custom traversal function - if (instance.isDeclaredInLibrary && (visitImpl = instance.lookupInSelf("__visit_impl"))) { + if (instance.isDeclaredInLibrary && (visitImpl = instance.lookupInSelf("__visit_impl")) !== null) { assert(visitImpl.kind == ElementKind.FUNCTION_PROTOTYPE); let visitFunc = program.resolver.resolveFunction(visitImpl, null); if (!visitFunc || !compiler.compileFunction(visitFunc)) { @@ -7686,7 +7726,7 @@ export function compileVisitMembers(compiler: Compiler): void { // for (let [instanceId, instance] of managedClasses) { for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { let instanceId = unchecked(_keys[i]); - let instance = managedClasses.get(instanceId)!; + let instance = assert(managedClasses.get(instanceId)); let base = instance.base; if (base) relooper.addBranch(blocks[instanceId], blocks[base.id]); } @@ -7733,7 +7773,7 @@ export function compileRTTI(compiler: Compiler): void { // for (let [instanceId, instance] of managedClasses) { for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { let instanceId = unchecked(_keys[i]); - let instance = managedClasses.get(instanceId)!; + let instance = assert(managedClasses.get(instanceId)); assert(instanceId == lastId++); let flags: TypeinfoFlags = 0; if (instance.isAcyclic) flags |= TypeinfoFlags.ACYCLIC; @@ -7796,7 +7836,7 @@ export function compileClassInstanceOf(compiler: Compiler, prototype: ClassProto // if (__instanceof(ref, ID[i])) return true var instances = prototype.instances; - if (instances !== null && instances.size) { + if (instances !== null && instances.size > 0) { // for (let instance of instances.values()) { for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); diff --git a/src/compiler.ts b/src/compiler.ts index bc94f06922..b4dd7d319d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -564,7 +564,7 @@ export class Compiler extends DiagnosticEmitter { // for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); - let member = members.get(memberName)!; + let member = assert(members.get(memberName)); this.ensureModuleExport(memberName, member); } } diff --git a/src/definitions.ts b/src/definitions.ts index bf537cdbef..ac1a31cdb0 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -72,7 +72,7 @@ export abstract class ExportsWalker { // for (let [memberName, member] of exports) { for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); - let member = exports.get(memberName)!; + let member = assert(exports.get(memberName)); this.visitElement(memberName, member); } } @@ -231,7 +231,7 @@ export class IDLBuilder extends ExportsWalker { // for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); - let member = members.get(memberName)!; + let member = assert(members.get(memberName)); if (member.kind == ElementKind.ENUMVALUE) { let value = member; let isConst = value.is(CommonFlags.INLINED); @@ -278,7 +278,7 @@ export class IDLBuilder extends ExportsWalker { } sb.push(");\n"); var members = element.members; - if (members !== null && members.size) { + if (members !== null && members.size > 0) { indent(sb, this.indentLevel); sb.push("interface "); sb.push(element.name); @@ -417,7 +417,7 @@ export class TSDBuilder extends ExportsWalker { // for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); - let member = members.get(memberName)!; + let member = assert(members.get(memberName)); if (member.kind == ElementKind.ENUMVALUE) { let value = member; indent(sb, this.indentLevel); @@ -532,7 +532,7 @@ export class TSDBuilder extends ExportsWalker { visitNamespace(name: string, element: Element): void { var members = element.members; - if (members !== null && members.size) { + if (members !== null && members.size > 0) { let sb = this.sb; indent(sb, this.indentLevel++); sb.push("export namespace "); diff --git a/src/diagnostics.ts b/src/diagnostics.ts index 82f3d32b4e..2f8054a03a 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -107,9 +107,9 @@ export class DiagnosticMessage { arg2: string | null = null ): DiagnosticMessage { var message = diagnosticCodeToString(code); - if (arg0 != null) message = message.replace("{0}", arg0); - if (arg1 != null) message = message.replace("{1}", arg1); - if (arg2 != null) message = message.replace("{2}", arg2); + if (arg0 !== null) message = message.replace("{0}", arg0); + if (arg1 !== null) message = message.replace("{1}", arg1); + if (arg2 !== null) message = message.replace("{2}", arg2); return new DiagnosticMessage(code, category, message); } @@ -127,7 +127,8 @@ export class DiagnosticMessage { /** Converts this message to a string. */ toString(): string { - if (this.range) { + var range = this.range; + if (range) { return ( diagnosticCategoryToString(this.category) + " " + @@ -135,11 +136,11 @@ export class DiagnosticMessage { ": \"" + this.message + "\" in " + - this.range.source.normalizedPath + + range.source.normalizedPath + ":" + - this.range.line.toString() + + range.line.toString() + ":" + - this.range.column.toString() + range.column.toString() ); } return ( @@ -170,10 +171,10 @@ export function formatDiagnosticMessage( sb.push(message.message); // include range information if available - if (message.range) { + var range = message.range; + if (range) { // include context information if requested - let range = message.range; if (showContext) { sb.push("\n"); sb.push(formatDiagnosticContext(range, useColors)); diff --git a/src/flow.ts b/src/flow.ts index c6a8d22c52..dab0fa05c8 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -331,31 +331,45 @@ export class Flow { assert(local.type != null); // internal error switch (local.type.toNativeType()) { case NativeType.I32: { - temps = parentFunction.tempI32s || (parentFunction.tempI32s = []); + let tempI32s = parentFunction.tempI32s; + if (tempI32s) temps = tempI32s; + else parentFunction.tempI32s = temps = []; break; } case NativeType.I64: { - temps = parentFunction.tempI64s || (parentFunction.tempI64s = []); + let tempI64s = parentFunction.tempI64s; + if (tempI64s) temps = tempI64s; + else parentFunction.tempI64s = temps = []; break; } case NativeType.F32: { - temps = parentFunction.tempF32s || (parentFunction.tempF32s = []); + let tempF32s = parentFunction.tempF32s; + if (tempF32s) temps = tempF32s; + else parentFunction.tempF32s = temps = []; break; } case NativeType.F64: { - temps = parentFunction.tempF64s || (parentFunction.tempF64s = []); + let tempF64s = parentFunction.tempF64s; + if (tempF64s) temps = tempF64s; + else parentFunction.tempF64s = temps = []; break; } case NativeType.V128: { - temps = parentFunction.tempV128s || (parentFunction.tempV128s = []); + let tempV128s = parentFunction.tempV128s; + if (tempV128s) temps = tempV128s; + else parentFunction.tempV128s = temps = []; break; } case NativeType.Anyref: { - temps = parentFunction.tempAnyrefs || (parentFunction.tempAnyrefs = []); + let tempAnyrefs = parentFunction.tempAnyrefs; + if (tempAnyrefs) temps = tempAnyrefs; + else parentFunction.tempAnyrefs = temps = []; break; } case NativeType.Exnref: { - temps = parentFunction.tempExnrefs || (parentFunction.tempExnrefs = []); + let tempExnrefs = parentFunction.tempExnrefs; + if (tempExnrefs) temps = tempExnrefs; + else parentFunction.tempExnrefs = temps = []; break; } default: throw new Error("concrete type expected"); @@ -935,11 +949,8 @@ export class Flow { case ExpressionId.Call: { let name = getCallTarget(expr); let program = this.parentFunction.program; - switch (name) { - case program.retainInstance.internalName: { - this.inheritNonnullIfTrue(getCallOperand(expr, 0), iff); - break; - } + if (name == program.retainInstance.internalName) { + this.inheritNonnullIfTrue(getCallOperand(expr, 0), iff); } break; } @@ -1308,7 +1319,7 @@ export class Flow { if (this.is(FlowFlags.CONDITIONALLY_BREAKS)) sb.push("CONDITIONALLY_BREAKS"); if (this.is(FlowFlags.CONDITIONALLY_CONTINUES)) sb.push("CONDITIONALLY_CONTINUES"); if (this.is(FlowFlags.CONDITIONALLY_ALLOCATES)) sb.push("CONDITIONALLY_ALLOCATES"); - return "Flow(" + this.actualFunction + ")[" + levels.toString() + "] " + sb.join(" "); + return "Flow(" + this.actualFunction.toString() + ")[" + levels.toString() + "] " + sb.join(" "); } } diff --git a/src/glue/wasm/float.ts b/src/glue/wasm/float.ts index a7a363a0b7..104994afef 100644 --- a/src/glue/wasm/float.ts +++ b/src/glue/wasm/float.ts @@ -1,20 +1,24 @@ /** @module glue/wasm *//***/ +// @ts-ignore: decorator @global function f32_as_i32(value: f32): i32 { return reinterpret(value); } +// @ts-ignore: decorator @global function i32_as_f32(value: i32): f32 { return reinterpret(value); } +// @ts-ignore: decorator @global function f64_as_i64(value: f64): i64 { return reinterpret(value); } +// @ts-ignore: decorator @global function i64_as_f64(value: i64): f64 { return reinterpret(value); diff --git a/src/glue/wasm/i64.ts b/src/glue/wasm/i64.ts index 5440824e79..753bd2f0fd 100644 --- a/src/glue/wasm/i64.ts +++ b/src/glue/wasm/i64.ts @@ -1,106 +1,128 @@ /** @module glue/wasm *//***/ +// @ts-ignore: decorator @global const i64_zero: i64 = 0; +// @ts-ignore: decorator @global const i64_one: i64 = 1; +// @ts-ignore: decorator @global function i64_new(lo: i32, hi: i32 = 0): i64 { return lo | (hi << 32); } +// @ts-ignore: decorator @global function i64_low(value: i64): i32 { return value; } +// @ts-ignore: decorator @global function i64_high(value: i64): i32 { return (value >>> 32); } +// @ts-ignore: decorator @global function i64_add(left: i64, right: i64): i64 { return left + right; } +// @ts-ignore: decorator @global function i64_sub(left: i64, right: i64): i64 { return left - right; } +// @ts-ignore: decorator @global function i64_mul(left: i64, right: i64): i64 { return left * right; } +// @ts-ignore: decorator @global function i64_div(left: i64, right: i64): i64 { return left / right; } +// @ts-ignore: decorator @global function i64_div_u(left: i64, right: i64): i64 { return left / right; } +// @ts-ignore: decorator @global function i64_rem(left: i64, right: i64): i64 { return left % right; } +// @ts-ignore: decorator @global function i64_rem_u(left: i64, right: i64): i64 { return left % right; } +// @ts-ignore: decorator @global function i64_and(left: i64, right: i64): i64 { return left & right; } +// @ts-ignore: decorator @global function i64_or(left: i64, right: i64): i64 { return left | right; } +// @ts-ignore: decorator @global function i64_xor(left: i64, right: i64): i64 { return left ^ right; } +// @ts-ignore: decorator @global function i64_shl(left: i64, right: i64): i64 { return left << right; } +// @ts-ignore: decorator @global function i64_shr(left: i64, right: i64): i64 { return left >> right; } +// @ts-ignore: decorator @global function i64_shr_u(left: i64, right: i64): i64 { return left >>> right; } +// @ts-ignore: decorator @global function i64_not(value: i64): i64 { return ~value; } +// @ts-ignore: decorator @global function i64_eq(left: i64, right: i64): bool { return left == right; } +// @ts-ignore: decorator @global function i64_ne(left: i64, right: i64): bool { return left != right; } +// @ts-ignore: decorator @global function i64_align(value: i64, alignment: i64): i64 { var mask: i64 = alignment - 1; @@ -108,56 +130,67 @@ function i64_align(value: i64, alignment: i64): i64 { return (value + mask) & ~mask; } +// @ts-ignore: decorator @global function i64_is_i8(value: i64): bool { - return value >= i8.MIN_VALUE && value <= i8.MAX_VALUE; + return value >= i8.MIN_VALUE && value <= i8.MAX_VALUE; } +// @ts-ignore: decorator @global function i64_is_i16(value: i64): bool { - return value >= i16.MIN_VALUE && value <= i16.MAX_VALUE; + return value >= i16.MIN_VALUE && value <= i16.MAX_VALUE; } +// @ts-ignore: decorator @global function i64_is_i32(value: i64): bool { - return value >= i32.MIN_VALUE && value <= i32.MAX_VALUE; + return value >= i32.MIN_VALUE && value <= i32.MAX_VALUE; } +// @ts-ignore: decorator @global function i64_is_u8(value: i64): bool { - return value >= 0 && value <= u8.MAX_VALUE; + return value >= 0 && value <= u8.MAX_VALUE; } +// @ts-ignore: decorator @global function i64_is_u16(value: i64): bool { - return value >= 0 && value <= u16.MAX_VALUE; + return value >= 0 && value <= u16.MAX_VALUE; } +// @ts-ignore: decorator @global function i64_is_u32(value: i64): bool { - return value >= 0 && value <= u32.MAX_VALUE; + return value >= 0 && value <= u32.MAX_VALUE; } +// @ts-ignore: decorator @global function i64_is_bool(value: i64): bool { return value === 0 || value === 1; } +// @ts-ignore: decorator @global function i64_is_f32(value: i64): bool { - return value >= f32.MIN_SAFE_INTEGER && value <= f32.MAX_SAFE_INTEGER; + return value >= f32.MIN_SAFE_INTEGER && value <= f32.MAX_SAFE_INTEGER; } +// @ts-ignore: decorator @global function i64_is_f64(value: i64): bool { - return value >= f64.MIN_SAFE_INTEGER && value <= f64.MAX_SAFE_INTEGER; + return value >= f64.MIN_SAFE_INTEGER && value <= f64.MAX_SAFE_INTEGER; } +// @ts-ignore: decorator @global function i64_to_f32(value: i64): f32 { return value; } +// @ts-ignore: decorator @global function i64_to_f64(value: i64): f64 { return value; @@ -165,15 +198,16 @@ function i64_to_f64(value: i64): f64 { import { CharCode } from "../../util"; +// @ts-ignore: decorator @global function i64_to_string(value: i64, unsigned: bool = false): string { - var chars = new Array(); + var chars = new Array(); if (!unsigned && value < 0) { chars.push(CharCode.MINUS); value = -value; } do { - chars.push(CharCode._0 + (value % 10)); + chars.push(CharCode._0 + (value % 10)); value = value / 10; } while (value); return String.fromCharCodes(chars); diff --git a/src/glue/wasm/mapset.ts b/src/glue/wasm/mapset.ts index e31d2debc3..cd040b37ac 100644 --- a/src/glue/wasm/mapset.ts +++ b/src/glue/wasm/mapset.ts @@ -1,13 +1,16 @@ +// @ts-ignore: decorator @global function Map_keys(map: Map): K[] { return map.keys(); // preliminary } +// @ts-ignore: decorator @global function Map_values(map: Map): V[] { return map.values(); // preliminary } +// @ts-ignore: decorator @global function Set_values(set: Set): V[] { return set.values(); // preliminary diff --git a/src/module.ts b/src/module.ts index 7c9c7d6fa0..0511cb04c7 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1241,10 +1241,10 @@ export class Module { : this.i32(i64_low(offset)); sizs[i] = buffer.length; } - var cArr1 = allocI32Array(segs); + var cArr1 = allocPtrArray(segs); var cArr2 = allocU8Array(psvs); - var cArr3 = allocI32Array(offs); - var cArr4 = allocI32Array(sizs); + var cArr3 = allocPtrArray(offs); + var cArr4 = allocU32Array(sizs); binaryen._BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, cArr4, k, shared); binaryen._free(cArr4); binaryen._free(cArr3); @@ -1269,7 +1269,7 @@ export class Module { for (let i = 0; i < numNames; ++i) { names[i] = this.allocStringCached(funcs[i]); } - var cArr = allocI32Array(names); + var cArr = allocPtrArray(names); binaryen._BinaryenSetFunctionTable(this.ref, initial, maximum, cArr, numNames, offset); binaryen._free(cArr); } @@ -1381,7 +1381,7 @@ export class Module { for (let i = 0; i < numNames; ++i) { names[i] = allocString(passes[i]); } - var cArr = allocI32Array(names); + var cArr = allocPtrArray(names); if (func) { binaryen._BinaryenFunctionRunPasses(func, this.ref, cArr, numNames); } else { @@ -1627,7 +1627,7 @@ export function expandType(type: NativeType): NativeType[] { var arity = binaryen._BinaryenTypeArity(type); var cArr = binaryen._malloc(arity << 2); binaryen._BinaryenTypeExpand(type, cArr); - var types = new Array(arity); + var types = new Array(arity); for (let i: u32 = 0; i < arity; ++i) { types[i] = binaryen.__i32_load(cArr + (i << 2)); } @@ -1990,8 +1990,30 @@ function allocI32Array(i32s: i32[] | null): usize { return ptr; } +function allocU32Array(u32s: u32[] | null): usize { + if (!u32s) return 0; + var ptr = binaryen._malloc(u32s.length << 2); + var idx = ptr; + for (let i = 0, k = u32s.length; i < k; ++i) { + let val = u32s[i]; + binaryen.__i32_store(idx, val); + idx += 4; + } + return ptr; +} + function allocPtrArray(ptrs: usize[] | null): usize { - return allocI32Array(ptrs); // TODO: WASM64 one day + if (!ptrs) return 0; + // TODO: WASM64 + assert(ASC_TARGET != Target.WASM64); + var ptr = binaryen._malloc(ptrs.length << 2); + var idx = ptr; + for (let i = 0, k = ptrs.length; i < k; ++i) { + let val = ptrs[i]; + binaryen.__i32_store(idx, val); + idx += 4; + } + return ptr; } function stringLengthUTF8(str: string): usize { diff --git a/src/parser.ts b/src/parser.ts index f1aca3ea11..8c6b7123a5 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -378,7 +378,7 @@ export class Parser extends DiagnosticEmitter { /** Obtains the next file to parse. */ nextFile(): string | null { var backlog = this.backlog; - return backlog.length ? backlog.shift()! : null; + return backlog.length ? assert(backlog.shift()) : null; } /** Obtains the dependee of the given imported file. */ @@ -1186,7 +1186,7 @@ export class Parser extends DiagnosticEmitter { while (!tn.skip(Token.CLOSEPAREN)) { let param = this.parseParameter(tn, isConstructor); // reports if (!param) return null; - if (seenRest && !reportedRest) { + if (seenRest !== null && !reportedRest) { this.error( DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list, seenRest.name.range @@ -1389,7 +1389,7 @@ export class Parser extends DiagnosticEmitter { name.range ); // recoverable } - if (parameters.length && parameters[0].initializer) { + if (parameters.length > 0 && parameters[0].initializer !== null) { this.error( DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, name.range @@ -1773,7 +1773,7 @@ export class Parser extends DiagnosticEmitter { if (!decorators) decorators = [decorator]; else decorators.push(decorator); } while (tn.skip(Token.AT)); - if (decorators && isInterface) { + if (decorators !== null && isInterface) { this.error( DiagnosticCode.Decorators_are_not_valid_here, Range.join(decorators[0].range, decorators[decorators.length - 1].range) @@ -2183,7 +2183,7 @@ export class Parser extends DiagnosticEmitter { if (!initializer) return null; } let range = tn.range(startPos, tn.pos); - if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && ((flags & CommonFlags.STATIC) || isInterface || initializer)) { + if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) != 0 && ((flags & CommonFlags.STATIC) != 0 || isInterface || initializer !== null)) { this.error( DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context, range @@ -2211,7 +2211,7 @@ export class Parser extends DiagnosticEmitter { // at: '[': 'key' ':' Type ']' ':' Type - if (decorators && decorators.length) { + if (decorators !== null && decorators.length > 0) { this.error( DiagnosticCode.Decorators_are_not_valid_here, Range.join(decorators[0].range, decorators[decorators.length - 1].range) @@ -2426,12 +2426,17 @@ export class Parser extends DiagnosticEmitter { return null; } } + if (asIdentifier) { + return Node.createExportMember( + identifier, + asIdentifier, + Range.join(identifier.range, asIdentifier.range) + ); + } return Node.createExportMember( identifier, - asIdentifier, - asIdentifier - ? Range.join(identifier.range, asIdentifier.range) - : identifier.range + null, + identifier.range ); } else { this.error( @@ -2586,12 +2591,17 @@ export class Parser extends DiagnosticEmitter { return null; } } + if (asIdentifier) { + return Node.createImportDeclaration( + identifier, + asIdentifier, + Range.join(identifier.range, asIdentifier.range) + ); + } return Node.createImportDeclaration( identifier, - asIdentifier, - asIdentifier - ? Range.join(identifier.range, asIdentifier.range) - : identifier.range + null, + identifier.range ); } else { this.error( diff --git a/src/program.ts b/src/program.ts index 2230a28ab4..f42376ce61 100644 --- a/src/program.ts +++ b/src/program.ts @@ -775,7 +775,7 @@ export class Program extends DiagnosticEmitter { // for (let [file, starExports] of queuedExportsStar) { for (let _keys = Map_keys(queuedExportsStar), i = 0, k = _keys.length; i < k; ++i) { let file = _keys[i]; - let starExports = queuedExportsStar.get(file)!; + let starExports = assert(queuedExportsStar.get(file)); for (let j = 0, l = starExports.length; j < l; ++j) { let exportStar = unchecked(starExports[j]); let foreignFile = this.lookupForeignFile(exportStar.foreignPath, exportStar.foreignPathAlt); @@ -837,11 +837,11 @@ export class Program extends DiagnosticEmitter { // for (let [file, exports] of queuedExports) { for (let _keys = Map_keys(queuedExports), i = 0, k = _keys.length; i < k; ++i) { let file = unchecked(_keys[i]); - let exports = queuedExports.get(file)!; + let exports = assert(queuedExports.get(file)); // for (let [exportName, queuedExport] of exports) { for (let exportNames = Map_keys(exports), j = 0, l = exportNames.length; j < l; ++j) { let exportName = unchecked(exportNames[j]); - let queuedExport = exports.get(exportName)!; + let queuedExport = assert(exports.get(exportName)); let localName = queuedExport.localIdentifier.text; let foreignPath = queuedExport.foreignPath; if (foreignPath) { // i.e. export { foo [as bar] } from "./baz" @@ -866,7 +866,7 @@ export class Program extends DiagnosticEmitter { file.ensureExport(exportName, element); } else { let globalElement = this.lookupGlobal(localName); - if (globalElement && globalElement instanceof DeclaredElement) { // export { memory } + if (globalElement !== null && isDeclaredElement(globalElement.kind)) { // export { memory } file.ensureExport(exportName, globalElement); } else { this.error( @@ -959,7 +959,7 @@ export class Program extends DiagnosticEmitter { // for (let [alias, name] of globalAliases) { for (let _keys = Map_keys(globalAliases), i = 0, k = _keys.length; i < k; ++i) { let alias = unchecked(_keys[i]); - let name = globalAliases.get(alias)!; + let name = assert(globalAliases.get(alias)); if (!name.length) continue; // explicitly disabled let firstChar = name.charCodeAt(0); if (firstChar >= CharCode._0 && firstChar <= CharCode._9) { @@ -1134,7 +1134,7 @@ export class Program extends DiagnosticEmitter { ensureGlobal(name: string, element: DeclaredElement): DeclaredElement { var elementsByName = this.elementsByName; if (elementsByName.has(name)) { - let existing = elementsByName.get(name)!; + let existing = assert(elementsByName.get(name)); // NOTE: this is effectively only performed when merging native types with // their respective namespaces in std/builtins, but can also trigger when a // user has multiple global elements of the same name in different files, @@ -1168,14 +1168,14 @@ export class Program extends DiagnosticEmitter { /** Looks up the element of the specified name in the global scope. */ lookupGlobal(name: string): Element | null { var elements = this.elementsByName; - if (elements.has(name)) return elements.get(name)!; + if (elements.has(name)) return assert(elements.get(name)); return null; } /** Looks up the element of the specified name in the global scope. Errors if not present. */ requireGlobal(name: string): Element { var elements = this.elementsByName; - if (elements.has(name)) return elements.get(name)!; + if (elements.has(name)) return assert(elements.get(name)); throw new Error("missing global"); } @@ -1188,9 +1188,9 @@ export class Program extends DiagnosticEmitter { ): File | null { var filesByName = this.filesByName; return filesByName.has(foreignPath) - ? filesByName.get(foreignPath)! + ? assert(filesByName.get(foreignPath)) : filesByName.has(foreignPathAlt) - ? filesByName.get(foreignPathAlt)! + ? assert(filesByName.get(foreignPathAlt)) : null; } @@ -1215,12 +1215,13 @@ export class Program extends DiagnosticEmitter { // otherwise traverse queued exports if (queuedExports.has(foreignFile)) { - let fileQueuedExports = queuedExports.get(foreignFile)!; + let fileQueuedExports = assert(queuedExports.get(foreignFile)); if (fileQueuedExports.has(foreignName)) { - let queuedExport = fileQueuedExports.get(foreignName)!; - if (queuedExport.foreignPath) { // imported from another file + let queuedExport = assert(fileQueuedExports.get(foreignName)); + let queuedExportForeignPath = queuedExport.foreignPath; + if (queuedExportForeignPath) { // imported from another file foreignName = queuedExport.localIdentifier.text; - foreignPath = queuedExport.foreignPath; + foreignPath = queuedExportForeignPath; foreignPathAlt = assert(queuedExport.foreignPathAlt); continue; } else { // local element of this file @@ -1441,7 +1442,8 @@ export class Program extends DiagnosticEmitter { case DecoratorKind.OPERATOR_BINARY: case DecoratorKind.OPERATOR_PREFIX: case DecoratorKind.OPERATOR_POSTFIX: { - let numArgs = decorator.arguments && decorator.arguments.length || 0; + let args = decorator.arguments; + let numArgs = args ? args.length : 0; if (numArgs == 1) { let firstArg = (decorator.arguments)[0]; if ( @@ -1495,8 +1497,8 @@ export class Program extends DiagnosticEmitter { var name = declaration.name.text; if (declaration.is(CommonFlags.STATIC)) { let parentMembers = parent.members; - if (parentMembers && parentMembers.has(name)) { - let element = parentMembers.get(name)!; + if (parentMembers !== null && parentMembers.has(name)) { + let element = assert(parentMembers.get(name)); if (element.kind == ElementKind.PROPERTY_PROTOTYPE) return element; } else { let element = new PropertyPrototype(name, parent, declaration); @@ -1505,8 +1507,8 @@ export class Program extends DiagnosticEmitter { } } else { let parentMembers = parent.instanceMembers; - if (parentMembers && parentMembers.has(name)) { - let element = parentMembers.get(name); + if (parentMembers !== null && parentMembers.has(name)) { + let element = assert(parentMembers.get(name)); if (element.kind == ElementKind.PROPERTY_PROTOTYPE) return element; } else { let element = new PropertyPrototype(name, parent, declaration); @@ -1627,7 +1629,7 @@ export class Program extends DiagnosticEmitter { } } else { // export * from "./baz" let queued: QueuedExportStar[]; - if (queuedExportsStar.has(parent)) queued = queuedExportsStar.get(parent)!; + if (queuedExportsStar.has(parent)) queued = assert(queuedExportsStar.get(parent)); else queuedExportsStar.set(parent, queued = []); let foreignPath = statement.internalPath!; // must be set for export * queued.push(new QueuedExportStar( @@ -1673,7 +1675,7 @@ export class Program extends DiagnosticEmitter { // otherwise queue it } else { let queued: Map; - if (queuedExports.has(localFile)) queued = queuedExports.get(localFile)!; + if (queuedExports.has(localFile)) queued = assert(queuedExports.get(localFile)); else queuedExports.set(localFile, queued = new Map()); queued.set(foreignName, new QueuedExport( member.localName, @@ -1685,7 +1687,7 @@ export class Program extends DiagnosticEmitter { // foreign element, i.e. export { foo } from "./bar" } else { let queued: Map; - if (queuedExports.has(localFile)) queued = queuedExports.get(localFile)!; + if (queuedExports.has(localFile)) queued = assert(queuedExports.get(localFile)); else queuedExports.set(localFile, queued = new Map()); queued.set(foreignName, new QueuedExport( member.localName, @@ -1738,7 +1740,7 @@ export class Program extends DiagnosticEmitter { if (!exports) parent.exports = exports = new Map(); else { if (exports.has("default")) { - let existing = exports.get("default")!; + let existing = assert(exports.get("default")); this.errorRelated( DiagnosticCode.Duplicate_identifier_0, declaration.name.range, @@ -1774,16 +1776,19 @@ export class Program extends DiagnosticEmitter { queuedExports ); } - } else if (statement.namespaceName) { // import * as foo from "./bar" - queuedImports.push(new QueuedImport( - parent, - statement.namespaceName, - null, // indicates import * - statement.internalPath, - statement.internalPath + INDEX_SUFFIX - )); } else { - // import "./foo" + let namespaceName = statement.namespaceName; + if (namespaceName) { // import * as foo from "./bar" + queuedImports.push(new QueuedImport( + parent, + namespaceName, + null, // indicates import * + statement.internalPath, + statement.internalPath + INDEX_SUFFIX + )); + } else { + // import "./foo" + } } } @@ -1902,7 +1907,7 @@ export class Program extends DiagnosticEmitter { queuedExtends: ClassPrototype[], /** So far queued `implements` clauses. */ queuedImplements: ClassPrototype[] - ): Namespace | null { + ): DeclaredElement | null { var name = declaration.name.text; var original = new Namespace( name, @@ -2186,7 +2191,7 @@ export abstract class Element { /** Looks up the element with the specified name within this element. */ lookupInSelf(name: string): DeclaredElement | null { var members = this.members; - if (members !== null && members.has(name)) return members.get(name)!; + if (members !== null && members.has(name)) return assert(members.get(name)); return null; } @@ -2425,7 +2430,7 @@ export class File extends Element { /** Looks up the export of the specified name. */ lookupExport(name: string): DeclaredElement | null { var exports = this.exports; - if (exports && exports.has(name)) return exports.get(name)!; + if (exports !== null && exports.has(name)) return assert(exports.get(name)); var exportsStar = this.exportsStar; if (exportsStar) { for (let i = 0, k = exportsStar.length; i < k; ++i) { @@ -2448,7 +2453,7 @@ export class File extends Element { // for (let [memberName, member] of exports) { for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); - let member = exports.get(memberName)!; + let member = assert(exports.get(memberName)); ns.add(memberName, member); } } @@ -2524,8 +2529,9 @@ export class Namespace extends DeclaredElement { /* @override */ lookup(name: string): Element | null { - return this.lookupInSelf(name) - || this.parent.lookup(name); + var inSelf = this.lookupInSelf(name); + if (inSelf) return inSelf; + return this.parent.lookup(name); } } @@ -2557,8 +2563,9 @@ export class Enum extends TypedElement { /* @override */ lookup(name: string): Element | null { - return this.lookupInSelf(name) - || this.parent.lookup(name); + var inSelf = this.lookupInSelf(name); + if (inSelf) return inSelf; + return this.parent.lookup(name); } } @@ -3304,7 +3311,7 @@ export class ClassPrototype extends DeclaredElement { var instanceMembers = this.instanceMembers; if (!instanceMembers) this.instanceMembers = instanceMembers = new Map(); else if (instanceMembers.has(name)) { - let existing = instanceMembers.get(name)!; + let existing = assert(instanceMembers.get(name)); let merged = tryMerge(existing, element); if (!merged) { if (isDeclaredElement(existing.kind)) { @@ -3585,8 +3592,10 @@ export class Class extends TypedElement { /** Gets the concrete type arguments to the specified extendend prototype. */ getTypeArgumentsTo(extendedPrototype: ClassPrototype): Type[] | null { var current: Class | null = this; - do if (current.prototype === extendedPrototype) return current.typeArguments; - while (current = current.base); + do { + if (current.prototype === extendedPrototype) return current.typeArguments; + current = current.base; + } while (current); return null; } @@ -3600,7 +3609,7 @@ export class Class extends TypedElement { } var prototype = current.prototype; if (prototype == program.arrayPrototype) { - return assert(this.getTypeArgumentsTo(program.arrayPrototype))[0]; + return this.getTypeArgumentsTo(program.arrayPrototype)![0]; } if (prototype == program.i8ArrayPrototype) return Type.i8; if (prototype == program.i16ArrayPrototype) return Type.i16; @@ -3629,7 +3638,7 @@ export class Class extends TypedElement { } /** Tests if this class potentially forms a reference cycle to another one. */ - private cyclesTo(other: Class, except: Set = new Set()): bool { + private cyclesTo(other: Class, except: Set = new Set()): bool { // TODO: The pure RC paper describes acyclic data structures as classes that may contain // // - scalars @@ -3666,7 +3675,7 @@ export class Class extends TypedElement { var basePrototype: ClassPrototype | null; // Arrayother?> - if ((basePrototype = this.program.arrayPrototype) && this.prototype.extends(basePrototype)) { + if ((basePrototype = this.program.arrayPrototype) !== null && this.prototype.extends(basePrototype)) { let typeArguments = assert(this.getTypeArgumentsTo(basePrototype)); assert(typeArguments.length == 1); if ( @@ -3678,7 +3687,7 @@ export class Class extends TypedElement { ) return true; // Setother?> - } else if ((basePrototype = this.program.setPrototype) && this.prototype.extends(basePrototype)) { + } else if ((basePrototype = this.program.setPrototype) !== null && this.prototype.extends(basePrototype)) { let typeArguments = assert(this.getTypeArgumentsTo(basePrototype)); assert(typeArguments.length == 1); if ( @@ -3690,7 +3699,7 @@ export class Class extends TypedElement { ) return true; // Mapother?,V->other?> - } else if ((basePrototype = this.program.mapPrototype) && this.prototype.extends(basePrototype)) { + } else if ((basePrototype = this.program.mapPrototype) !== null && this.prototype.extends(basePrototype)) { let typeArguments = assert(this.getTypeArgumentsTo(basePrototype)); assert(typeArguments.length == 2); if ( diff --git a/src/resolver.ts b/src/resolver.ts index bc0a594f18..5a527b9392 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -281,12 +281,11 @@ export class Resolver extends DiagnosticEmitter { // Handle special built-in types if (isSimpleType) { - switch (nameNode.identifier.text) { - case CommonNames.native: return this.resolveBuiltinNativeType(node, ctxElement, ctxTypes, reportMode); - case CommonNames.indexof: return this.resolveBuiltinIndexofType(node, ctxElement, ctxTypes, reportMode); - case CommonNames.valueof: return this.resolveBuiltinValueofType(node, ctxElement, ctxTypes, reportMode); - case CommonNames.returnof: return this.resolveBuiltinReturnTypeType(node, ctxElement, ctxTypes, reportMode); - } + let text = nameNode.identifier.text; + if (text == CommonNames.native) return this.resolveBuiltinNativeType(node, ctxElement, ctxTypes, reportMode); + if (text == CommonNames.indexof) return this.resolveBuiltinIndexofType(node, ctxElement, ctxTypes, reportMode); + if (text == CommonNames.valueof) return this.resolveBuiltinValueofType(node, ctxElement, ctxTypes, reportMode); + if (text == CommonNames.returnof) return this.resolveBuiltinReturnTypeType(node, ctxElement, ctxTypes, reportMode); } // Resolve normally @@ -665,7 +664,7 @@ export class Resolver extends DiagnosticEmitter { typeArgumentNodes![0].range, typeArgumentNodes![argumentCount - 1].range ) - : assert(alternativeReportNode).range, + : alternativeReportNode!.range, (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(), argumentCount.toString() ); @@ -2874,7 +2873,8 @@ export class Resolver extends DiagnosticEmitter { ); return null; } - } while (current = current.basePrototype); + current = current.basePrototype; + } while (current); let extendsNode = assert(prototype.extendsNode); // must be present if it has a base prototype let base = this.resolveClassInclTypeArguments( basePrototype, @@ -2920,7 +2920,7 @@ export class Resolver extends DiagnosticEmitter { // for (let [baseMemberName, baseMember] of baseMembers) { for (let _keys = Map_keys(baseMembers), i = 0, k = _keys.length; i < k; ++i) { let baseMemberName = unchecked(_keys[i]); - let baseMember = baseMembers.get(baseMemberName)!; + let baseMember = assert(baseMembers.get(baseMemberName)); instanceMembers.set(baseMemberName, baseMember); } } diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 02af3d2ee7..fc30fdc545 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -171,7 +171,7 @@ declare function isManaged(value?: any): bool; /** Tests if the specified type is void. Compiles to a constant. */ declare function isVoid(): bool; /** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */ -declare function assert(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? +declare function assert(isTrueish: T, message?: string): T & (object | string | number); // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; /** Parses a string to a 64-bit float. */ diff --git a/std/assembly/string.ts b/std/assembly/string.ts index b2065c8de5..4ac260aaed 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -5,6 +5,7 @@ import { compareImpl, strtol, strtod, isSpace, isAscii, toLower8, toUpper8 } fro import { SPECIALS_UPPER, casemap, bsearch } from "./util/casemap"; import { E_INVALIDLENGTH } from "./util/error"; import { idof } from "./builtins"; +import { Array} from "./array"; @sealed export abstract class String { @@ -18,6 +19,16 @@ import { idof } from "./builtins"; return changetype(out); // retains } + static fromCharCodes(units: Array): String { + var length = units.length; + var out = __alloc(length << 1, idof()); + var ptr = units.dataStart; + for (let i = 0; i < length; ++i) { + store(out + (i << 1), load(ptr + (i << 2))); + } + return changetype(out); + } + static fromCodePoint(code: i32): String { assert(code <= 0x10FFFF); var hasSur = code > 0xFFFF; diff --git a/std/portable/index.d.ts b/std/portable/index.d.ts index eb400dcf4b..df78e5ac25 100644 --- a/std/portable/index.d.ts +++ b/std/portable/index.d.ts @@ -108,7 +108,7 @@ declare function isDefined(expression: any): bool; /** Tests if the specified expression evaluates to a constant value. */ declare function isConstant(expression: any): bool; /** Traps if the specified value is not true-ish, otherwise returns the value. */ -declare function assert(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? +declare function assert(isTrueish: T, message?: string): T & (object | string | number); // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; /** Parses a floating point string to a 64-bit float. */ diff --git a/tests/compiler/std/string-encoding.optimized.wat b/tests/compiler/std/string-encoding.optimized.wat index 399fa1dab2..5a1f9897c4 100644 --- a/tests/compiler/std/string-encoding.optimized.wat +++ b/tests/compiler/std/string-encoding.optimized.wat @@ -2111,7 +2111,7 @@ if i32.const 0 i32.const 432 - i32.const 700 + i32.const 711 i32.const 6 call $~lib/builtins/abort unreachable @@ -2592,7 +2592,7 @@ if i32.const 0 i32.const 432 - i32.const 716 + i32.const 727 i32.const 6 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string-encoding.untouched.wat b/tests/compiler/std/string-encoding.untouched.wat index d3aca02840..5f5792c465 100644 --- a/tests/compiler/std/string-encoding.untouched.wat +++ b/tests/compiler/std/string-encoding.untouched.wat @@ -3745,7 +3745,7 @@ if i32.const 0 i32.const 432 - i32.const 700 + i32.const 711 i32.const 6 call $~lib/builtins/abort unreachable @@ -4300,7 +4300,7 @@ if i32.const 0 i32.const 432 - i32.const 716 + i32.const 727 i32.const 6 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string.optimized.wat b/tests/compiler/std/string.optimized.wat index 272b5d04cf..99cb679912 100644 --- a/tests/compiler/std/string.optimized.wat +++ b/tests/compiler/std/string.optimized.wat @@ -1782,7 +1782,7 @@ if i32.const 0 i32.const 528 - i32.const 22 + i32.const 33 i32.const 4 call $~lib/builtins/abort unreachable @@ -4394,7 +4394,7 @@ if i32.const 10896 i32.const 528 - i32.const 311 + i32.const 322 i32.const 6 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string.untouched.wat b/tests/compiler/std/string.untouched.wat index fa78101e02..520340a68f 100644 --- a/tests/compiler/std/string.untouched.wat +++ b/tests/compiler/std/string.untouched.wat @@ -2230,7 +2230,7 @@ if i32.const 0 i32.const 528 - i32.const 22 + i32.const 33 i32.const 4 call $~lib/builtins/abort unreachable @@ -6997,7 +6997,7 @@ if i32.const 10896 i32.const 528 - i32.const 311 + i32.const 322 i32.const 6 call $~lib/builtins/abort unreachable From e904e25dfab4027800b2997ca23e75fe37e498f5 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 00:20:20 +0100 Subject: [PATCH 10/28] refactor hell part 4, down to 29 --- src/ast.ts | 2 +- src/compiler.ts | 150 +++++++++++++------------ src/flow.ts | 41 ++++--- src/module.ts | 29 +++-- src/parser.ts | 12 +- src/program.ts | 50 +++++---- src/resolver.ts | 81 +++++++------ src/tokenizer.ts | 13 +-- src/types.ts | 15 ++- tests/compiler/loop-wrap.optimized.wat | 20 ++-- tests/compiler/loop-wrap.untouched.wat | 24 ++-- tests/compiler/std/libm.untouched.wat | 3 +- tests/compiler/std/math.untouched.wat | 3 +- tests/packages/packages/g/test.js | 2 +- 14 files changed, 238 insertions(+), 207 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index 44e207f34f..440fc0efb2 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -1146,7 +1146,7 @@ export abstract class TypeNode extends Node { if (this.kind == NodeKind.NAMEDTYPE) { if (!(self).name.next) { let typeArgumentNodes = (self).typeArguments; - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { for (let i = 0, k = typeArgumentNodes.length; i < k; ++i) { if (typeArgumentNodes[i].hasGenericComponent(typeParameterNodes)) return true; } diff --git a/src/compiler.ts b/src/compiler.ts index b4dd7d319d..fa0512a2ff 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -29,6 +29,7 @@ import { ExpressionId, GlobalRef, FeatureFlags, + Index, getExpressionId, getExpressionType, getConstValueI32, @@ -808,9 +809,9 @@ export class Compiler extends DiagnosticEmitter { var filesByName = this.program.filesByName; var pathWithIndex: string; if (filesByName.has(normalizedPathWithoutExtension)) { - file = filesByName.get(normalizedPathWithoutExtension)!; + file = assert(filesByName.get(normalizedPathWithoutExtension)); } else if (filesByName.has(pathWithIndex = normalizedPathWithoutExtension + INDEX_SUFFIX)) { - file = filesByName.get(pathWithIndex)!; + file = assert(filesByName.get(pathWithIndex)); } else { this.error( DiagnosticCode.File_0_not_found, @@ -995,7 +996,7 @@ export class Compiler extends DiagnosticEmitter { if (!isGlobalMutable(module.getGlobal(fromName))) { let elementsByName = this.program.elementsByName; if (elementsByName.has(fromName)) { - let global = elementsByName.get(fromName)!; + let global = assert(elementsByName.get(fromName)); if (global.is(CommonFlags.AMBIENT)) initializeInStart = false; } } @@ -1059,7 +1060,7 @@ export class Compiler extends DiagnosticEmitter { if (isDeclaredInline) { this.error( DiagnosticCode.Decorator_0_is_not_valid_here, - assert(findDecorator(DecoratorKind.INLINE, global.decoratorNodes)).range, "inline" + findDecorator(DecoratorKind.INLINE, global.decoratorNodes)!.range, "inline" ); } module.addGlobal(internalName, nativeType, true, this.makeZero(type)); @@ -1087,9 +1088,10 @@ export class Compiler extends DiagnosticEmitter { var previousValueIsMut = false; var isInline = element.is(CommonFlags.CONST) || element.hasDecorator(DecoratorFlags.INLINE); - if (element.members) { + var members = element.members; + if (members) { // for (let member of element.members.values()) { - for (let _values = Map_values(element.members), i = 0, k = _values.length; i < k; ++i) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) continue; // happens if an enum is also a namespace let initInStart = false; @@ -1348,7 +1350,9 @@ export class Compiler extends DiagnosticEmitter { if (instance.is(CommonFlags.CONSTRUCTOR)) { let nativeSizeType = this.options.nativeSizeType; assert(instance.is(CommonFlags.INSTANCE)); - let classInstance = assert(instance.parent); assert(classInstance.kind == ElementKind.CLASS); + let parent = assert(instance.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; if (!flow.is(FlowFlags.TERMINATES)) { let thisLocal = assert(flow.lookupLocal(CommonNames.this_)); @@ -1367,12 +1371,12 @@ export class Compiler extends DiagnosticEmitter { ), module.local_set(thisLocal.index, this.makeRetain( - this.makeAllocation(classInstance) + this.makeAllocation(classInstance) ), ) ) ); - this.makeFieldInitializationInConstructor(classInstance, stmts); + this.makeFieldInitializationInConstructor(classInstance, stmts); } this.performAutoreleases(flow, stmts); // `this` is excluded anyway this.finishAutoreleases(flow, stmts); @@ -1381,7 +1385,7 @@ export class Compiler extends DiagnosticEmitter { } // check that super has been called if this is a derived class - if ((classInstance).base && !flow.is(FlowFlags.CALLS_SUPER)) { + if (classInstance.base !== null && !flow.is(FlowFlags.CALLS_SUPER)) { this.error( DiagnosticCode.Constructors_for_derived_classes_must_contain_a_super_call, instance.prototype.declaration.range @@ -1597,7 +1601,7 @@ export class Compiler extends DiagnosticEmitter { var stringSegment: MemorySegment; var segments = this.stringSegments; if (segments.has(stringValue)) { - stringSegment = segments.get(stringValue)!; // reuse + stringSegment = assert(segments.get(stringValue)); // reuse } else { let length = stringValue.length; let buffer = new Uint8Array(rtHeaderSize + (length << 1)); @@ -1949,7 +1953,7 @@ export class Compiler extends DiagnosticEmitter { switch (getExpressionId(stmt)) { case ExpressionId.Block: { if (!getBlockName(stmt)) { - for (let j = 0, k = getBlockChildCount(stmt); j < k; ++j) stmts.push(getBlockChild(stmt, j)); + for (let j: Index = 0, k = getBlockChildCount(stmt); j < k; ++j) stmts.push(getBlockChild(stmt, j)); break; } // fall-through @@ -1985,10 +1989,11 @@ export class Compiler extends DiagnosticEmitter { statement: BreakStatement ): ExpressionRef { var module = this.module; - if (statement.label) { + var labelNode = statement.label; + if (labelNode) { this.error( DiagnosticCode.Not_implemented, - statement.label.range + labelNode.range ); return module.unreachable(); } @@ -2040,7 +2045,7 @@ export class Compiler extends DiagnosticEmitter { var stmts = new Array(); this.performAutoreleases(flow, stmts); var current: Flow | null = flow.parent; - while (current && current.continueLabel === continueLabel) { + while (current !== null && current.continueLabel === continueLabel) { this.performAutoreleases(current, stmts, /* finalize */ false); current = current.parent; } @@ -2148,7 +2153,7 @@ export class Compiler extends DiagnosticEmitter { assert(!flowAfter); // should work on the first attempt outerFlow.popBreakLabel(); this.currentFlow = outerFlow; - return this.doCompileWhileStatement(statement, flow); + return this.doCompileDoStatement(statement, flow); } } } @@ -2541,7 +2546,7 @@ export class Compiler extends DiagnosticEmitter { this.performAutoreleases(flow, stmts); this.finishAutoreleases(flow, stmts); - if (returnType != Type.void && stmts.length) { + if (returnType != Type.void && stmts.length > 0) { let temp = flow.getTempLocal(returnType); if (flow.isNonnull(expr, returnType)) flow.setLocalFlag(temp.index, LocalFlags.NONNULL); stmts.unshift( @@ -2553,7 +2558,7 @@ export class Compiler extends DiagnosticEmitter { flow.freeScopedLocals(); // If the last statement anyway, make it the block's return value - if (isLastInBody && expr && returnType != Type.void) { + if (isLastInBody && expr != 0 && returnType != Type.void) { if (!stmts.length) return expr; stmts.push(expr); return module.flatten(stmts, returnType.toNativeType()); @@ -2743,23 +2748,25 @@ export class Compiler extends DiagnosticEmitter { let initAutoreleaseSkipped = false; // Resolve type if annotated - if (declaration.type) { + let typeNode = declaration.type; + let initializerNode = declaration.initializer; + if (typeNode) { type = resolver.resolveType( // reports - declaration.type, + typeNode, flow.actualFunction, makeMap(flow.contextualTypeArguments) ); if (!type) continue; - if (declaration.initializer) { - initExpr = this.compileExpression(declaration.initializer, type, // reports + if (initializerNode) { + initExpr = this.compileExpression(initializerNode, type, // reports Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN ); initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr); } // Otherwise infer type from initializer - } else if (declaration.initializer) { - initExpr = this.compileExpression(declaration.initializer, Type.auto, + } else if (initializerNode) { + initExpr = this.compileExpression(initializerNode, Type.auto, Constraints.WILL_RETAIN ); // reports initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr); @@ -2827,7 +2834,7 @@ export class Compiler extends DiagnosticEmitter { let scopedLocals = flow.scopedLocals; if (!scopedLocals) flow.scopedLocals = scopedLocals = new Map(); else if (scopedLocals.has(name)) { - let existing = scopedLocals.get(name)!; + let existing = assert(scopedLocals.get(name)); this.errorRelated( DiagnosticCode.Duplicate_identifier_0, declaration.name.range, @@ -3152,13 +3159,13 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.F64: { // monkey-patch for converting built-in floats to f32 implicitly if (!(element.hasDecorator(DecoratorFlags.BUILTIN) && contextualType == Type.f32)) { - return this.module.f64((element).constantFloatValue); + return this.module.f64(element.constantFloatValue); } // otherwise fall-through: basically precomputes f32.demote/f64 of NaN / Infinity this.currentType = Type.f32; } case TypeKind.F32: { - return this.module.f32((element).constantFloatValue); + return this.module.f32(element.constantFloatValue); } default: { assert(false); @@ -3639,18 +3646,8 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, true)) { - leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, - false, true, // ! - left - ); - rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, - false, true, // ! - right - ); - } else { + commonType = Type.commonDenominator(leftType, rightType, true); + if (!commonType) { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, expression.range, "<", leftType.toString(), rightType.toString() @@ -3658,6 +3655,16 @@ export class Compiler extends DiagnosticEmitter { this.currentType = contextualType; return module.unreachable(); } + leftExpr = this.convertExpression(leftExpr, + leftType, leftType = commonType, + false, true, // ! + left + ); + rightExpr = this.convertExpression(rightExpr, + rightType, rightType = commonType, + false, true, // ! + right + ); switch (commonType.kind) { case TypeKind.I8: case TypeKind.I16: @@ -3739,7 +3746,8 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, true)) { + commonType = Type.commonDenominator(leftType, rightType, true); + if (commonType) { leftExpr = this.convertExpression(leftExpr, leftType, leftType = commonType, false, true, // ! @@ -4574,7 +4582,7 @@ export class Compiler extends DiagnosticEmitter { this.f64PowInstance = instance = this.resolver.resolveFunction(prototype, null); } } - if (!(instance && this.compileFunction(instance))) { + if (!instance || !this.compileFunction(instance)) { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); @@ -4815,7 +4823,7 @@ export class Compiler extends DiagnosticEmitter { assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE); this.f32ModInstance = instance = this.resolver.resolveFunction(prototype, null); } - if (!(instance && this.compileFunction(instance))) { + if (!instance || !this.compileFunction(instance)) { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); @@ -4846,7 +4854,7 @@ export class Compiler extends DiagnosticEmitter { assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE); this.f64ModInstance = instance = this.resolver.resolveFunction(prototype, null); } - if (!(instance && this.compileFunction(instance))) { + if (!instance || !this.compileFunction(instance)) { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); @@ -5577,7 +5585,8 @@ export class Compiler extends DiagnosticEmitter { var resolver = this.resolver; var target = resolver.lookupExpression(left, this.currentFlow); if (!target) return module.unreachable(); - var targetType = resolver.getTypeOfElement(target) || Type.void; + var targetType = resolver.getTypeOfElement(target); + if (!targetType) targetType = Type.void; if (!this.currentType.isStrictlyAssignableTo(targetType)) { this.error( DiagnosticCode.Type_0_is_not_assignable_to_type_1, @@ -5665,7 +5674,7 @@ export class Compiler extends DiagnosticEmitter { ); return this.module.unreachable(); } - let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); + let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); if (!setterInstance) return this.module.unreachable(); assert(setterInstance.signature.parameterTypes.length == 1); // parser must guarantee this targetType = setterInstance.signature.parameterTypes[0]; @@ -5794,7 +5803,7 @@ export class Compiler extends DiagnosticEmitter { (target).is(CommonFlags.READONLY) && !( flow.actualFunction.is(CommonFlags.CONSTRUCTOR) || - initializerNode + initializerNode !== null ) ) { this.error( @@ -5819,7 +5828,7 @@ export class Compiler extends DiagnosticEmitter { ); return module.unreachable(); } - let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); + let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); if (!setterInstance) return module.unreachable(); assert(setterInstance.signature.parameterTypes.length == 1); let valueType = setterInstance.signature.parameterTypes[0]; @@ -5828,7 +5837,7 @@ export class Compiler extends DiagnosticEmitter { if (!tee) return this.makeCallDirect(setterInstance, [ valueExpr ], valueExpression); // otherwise call the setter first, then the getter let getterPrototype = assert((target).getterPrototype); // must be present - let getterInstance = this.resolver.resolveFunction(getterPrototype, null, makeMap(), ReportMode.REPORT); + let getterInstance = this.resolver.resolveFunction(getterPrototype, null, makeMap(), ReportMode.REPORT); if (!getterInstance) return module.unreachable(); let returnType = getterInstance.signature.returnType; assert(valueType == returnType); @@ -6003,8 +6012,8 @@ export class Compiler extends DiagnosticEmitter { /** Makes an assignment to a global, possibly retaining and releasing affected references. */ private makeGlobalAssignment( - /** The global to assign to. */ - global: Global, + /** The global variable to assign to. */ + global: VariableLikeElement, /** The value to assign. */ valueExpr: ExpressionRef, /** Whether to tee the value. */ @@ -6393,7 +6402,7 @@ export class Compiler extends DiagnosticEmitter { ctx.contextIsExact = false; var internalName = prototype.internalName; if (builtins.has(internalName)) { - let fn = builtins.get(internalName)!; + let fn = assert(builtins.get(internalName)); return fn(ctx); } this.error( @@ -7553,7 +7562,7 @@ export class Compiler extends DiagnosticEmitter { var internalPath = expression.range.source.internalPath; var filesByName = this.program.filesByName; assert(filesByName.has(internalPath)); - var enclosingFile = filesByName.get(internalPath)!; + var enclosingFile = assert(filesByName.get(internalPath)); if (!enclosingFile.is(CommonFlags.COMPILED)) { this.compileFileByPath(internalPath, expression); } @@ -7692,10 +7701,12 @@ export class Compiler extends DiagnosticEmitter { this.maybeCompileEnclosingSource(expression); // otherwise resolve + var currentParent = this.currentParent; + if (!currentParent) currentParent = actualFunction; var target = this.resolver.lookupIdentifierExpression( // reports expression, flow, - this.currentParent || actualFunction + currentParent ); if (!target) { // make a guess to avoid assertions in calling code @@ -7761,7 +7772,7 @@ export class Compiler extends DiagnosticEmitter { null, makeMap(flow.contextualTypeArguments) ); - if (!(instance && this.compileFunction(instance))) return module.unreachable(); + if (!instance || !this.compileFunction(instance)) return module.unreachable(); if (contextualType.is(TypeFlags.HOST | TypeFlags.REFERENCE)) { this.currentType = Type.anyref; return module.ref_func(instance.internalName); @@ -8089,7 +8100,7 @@ export class Compiler extends DiagnosticEmitter { assert(element.kind == ElementKind.CLASS); var arrayInstance = element; var arrayType = arrayInstance.type; - var elementType = assert(arrayInstance.getTypeArgumentsTo(program.arrayPrototype))[0]; + var elementType = arrayInstance.getTypeArgumentsTo(program.arrayPrototype)![0]; var arrayBufferInstance = assert(program.arrayBufferInstance); // block those here so compiling expressions doesn't conflict @@ -8259,7 +8270,7 @@ export class Compiler extends DiagnosticEmitter { assert(contextualType.is(TypeFlags.REFERENCE)); var arrayInstance = assert(contextualType.classReference); var arrayType = arrayInstance.type; - var elementType = assert(arrayInstance.getTypeArgumentsTo(program.staticArrayPrototype))[0]; + var elementType = arrayInstance.getTypeArgumentsTo(program.staticArrayPrototype)![0]; // block those here so compiling expressions doesn't conflict var tempThis = flow.getTempLocal(this.options.usizeType); @@ -8777,7 +8788,6 @@ export class Compiler extends DiagnosticEmitter { ): ExpressionRef { var ifThen = expression.ifThen; var ifElse = expression.ifElse; - var outerFlow = this.currentFlow; var condExpr = this.module.precomputeExpression( this.makeIsTrueish( @@ -8787,27 +8797,25 @@ export class Compiler extends DiagnosticEmitter { ); // Try to eliminate unnecesssary branches if the condition is constant - // FIXME: skips common denominator, inconsistently picking left type - if ( - getExpressionId(condExpr) == ExpressionId.Const && - getExpressionType(condExpr) == NativeType.I32 - ) { - return getConstValueI32(condExpr) - ? this.compileExpression(ifThen, ctxType) - : this.compileExpression(ifElse, ctxType); - } + // FIXME: skips common denominator, inconsistently picking branch type + var condKind = evaluateConditionKind(condExpr); + if (condKind == ConditionKind.TRUE) return this.compileExpression(ifThen, ctxType); + if (condKind == ConditionKind.FALSE) return this.compileExpression(ifElse, ctxType); var inheritedConstraints = constraints & Constraints.WILL_RETAIN; + var outerFlow = this.currentFlow; var ifThenFlow = outerFlow.fork(); + ifThenFlow.inheritNonnullIfTrue(condExpr); this.currentFlow = ifThenFlow; var ifThenExpr = this.compileExpression(ifThen, ctxType, inheritedConstraints); var ifThenType = this.currentType; var ifThenAutoreleaseSkipped = this.skippedAutoreleases.has(ifThenExpr); var ifElseFlow = outerFlow.fork(); + ifElseFlow.inheritNonnullIfFalse(condExpr); this.currentFlow = ifElseFlow; - var ifElseExpr = this.compileExpression(ifElse, ctxType, inheritedConstraints); + var ifElseExpr = this.compileExpression(ifElse, ctxType == Type.auto ? ifThenType : ctxType, inheritedConstraints); var ifElseType = this.currentType; var ifElseAutoreleaseSkipped = this.skippedAutoreleases.has(ifElseExpr); @@ -9819,7 +9827,7 @@ export class Compiler extends DiagnosticEmitter { var flow = this.currentFlow; var isInline = flow.isInline; var thisLocalIndex = isInline - ? assert(flow.lookupLocal(CommonNames.this_)).index + ? flow.lookupLocal(CommonNames.this_)!.index : 0; var nativeSizeType = this.options.nativeSizeType; @@ -9844,7 +9852,7 @@ export class Compiler extends DiagnosticEmitter { if (parameterIndex >= 0) { initExpr = module.local_get( isInline - ? assert(flow.lookupLocal(field.name)).index + ? flow.lookupLocal(field.name)!.index : 1 + parameterIndex, // this is local 0 nativeFieldType ); @@ -9959,7 +9967,7 @@ export class Compiler extends DiagnosticEmitter { expr = module.if( module.call(instanceofInstance.internalName, [ module.local_tee(temp.index, expr), - module.i32(assert(toType.classReference).id) + module.i32(toType.classReference!.id) ], NativeType.I32), module.local_get(temp.index, type.toNativeType()), this.makeAbort(null, reportNode) // TODO: throw @@ -9988,7 +9996,7 @@ function mangleImportName( var program = element.program; var decorator = assert(findDecorator(DecoratorKind.EXTERNAL, declaration.decorators)); var args = decorator.arguments; - if (args && args.length) { + if (args !== null && args.length > 0) { let arg = args[0]; // if one argument is given, override just the element name // if two arguments are given, override both module and element name diff --git a/src/flow.ts b/src/flow.ts index dab0fa05c8..17a5afc206 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -283,7 +283,7 @@ export class Flow { } var local: Local; if (except) { - if (temps && temps.length) { + if (temps !== null && temps.length > 0) { for (let i = 0, k = temps.length; i < k; ++i) { if (!except.has(temps[i].index)) { local = temps[i]; @@ -299,8 +299,8 @@ export class Flow { } local = parentFunction.addLocal(type); } else { - if (temps && temps.length) { - local = temps.pop()!; + if (temps !== null && temps.length > 0) { + local = assert(temps.pop()); local.type = type; local.flags = CommonFlags.NONE; } else { @@ -317,7 +317,7 @@ export class Flow { local.set(CommonFlags.SCOPED); var scopedLocals = this.scopedLocals; if (!scopedLocals) this.scopedLocals = scopedLocals = new Map(); - scopedLocals.set("~auto" + (this.parentFunction.nextAutoreleaseId++), local); + scopedLocals.set("~auto" + (this.parentFunction.nextAutoreleaseId++).toString(), local); this.setLocalFlag(local.index, LocalFlags.RETAINED); return local; } @@ -381,7 +381,7 @@ export class Flow { /** Gets the scoped local of the specified name. */ getScopedLocal(name: string): Local | null { var scopedLocals = this.scopedLocals; - if (scopedLocals && scopedLocals.has(name)) return scopedLocals.get(name)!; + if (scopedLocals !== null && scopedLocals.has(name)) return assert(scopedLocals.get(name)); return null; } @@ -460,10 +460,14 @@ export class Flow { /** Looks up the local of the specified name in the current scope. */ lookupLocal(name: string): Local | null { var current: Flow | null = this; - var scope: Map | null; - do if ((scope = current.scopedLocals) && scope.has(name)) return scope.get(name)!; - while (current = current.parent); - return this.parentFunction.localsByName.get(name)!; + do { + let scope = current.scopedLocals; + if (scope !== null && scope.has(name)) return assert(scope.get(name)); + current = current.parent; + } while (current); + var localsByName = this.parentFunction.localsByName; + if (localsByName.has(name)) return assert(localsByName.get(name)); + return null; } /** Looks up the element with the specified name relative to the scope of this flow. */ @@ -510,7 +514,9 @@ export class Flow { var stack = parentFunction.breakStack; if (!stack) parentFunction.breakStack = [ id ]; else stack.push(id); - return parentFunction.breakLabel = id.toString(); + var label = id.toString(); + parentFunction.breakLabel = label; + return label; } /** Pops the most recent break label from the stack. */ @@ -950,6 +956,7 @@ export class Flow { let name = getCallTarget(expr); let program = this.parentFunction.program; if (name == program.retainInstance.internalName) { + // __retain just passes through the argument this.inheritNonnullIfTrue(getCallOperand(expr, 0), iff); } break; @@ -1076,7 +1083,7 @@ export class Flow { // overflows if the conversion does (globals are wrapped on set) case ExpressionId.GlobalGet: { // TODO: this is inefficient because it has to read a string - let global = assert(this.parentFunction.program.elementsByName.get(assert(getGlobalGetName(expr)))!); + let global = assert(this.parentFunction.program.elementsByName.get(assert(getGlobalGetName(expr)))); assert(global.kind == ElementKind.GLOBAL); return canConversionOverflow(assert((global).type), type); } @@ -1231,10 +1238,10 @@ export class Flow { default: assert(false); } switch (type.kind) { - case TypeKind.I8: return value < i8.MIN_VALUE || value > i8.MAX_VALUE; - case TypeKind.I16: return value < i16.MIN_VALUE || value > i16.MAX_VALUE; - case TypeKind.U8: return value < 0 || value > u8.MAX_VALUE; - case TypeKind.U16: return value < 0 || value > u16.MAX_VALUE; + case TypeKind.I8: return value < i8.MIN_VALUE || value > i8.MAX_VALUE; + case TypeKind.I16: return value < i16.MIN_VALUE || value > i16.MAX_VALUE; + case TypeKind.U8: return value < 0 || value > u8.MAX_VALUE; + case TypeKind.U16: return value < 0 || value > u16.MAX_VALUE; case TypeKind.BOOL: return (value & ~1) != 0; } break; @@ -1282,7 +1289,7 @@ export class Flow { let instancesByName = program.instancesByName; let instanceName = assert(getCallTarget(expr)); if (instancesByName.has(instanceName)) { - let instance = instancesByName.get(instanceName)!; + let instance = assert(instancesByName.get(instanceName)); assert(instance.kind == ElementKind.FUNCTION); let returnType = (instance).signature.returnType; return !(instance).flow.is(FlowFlags.RETURNS_WRAPPED) @@ -1331,7 +1338,7 @@ function canConversionOverflow(fromType: Type, toType: Type): bool { } /** Finds all indexes of locals used in the specified expression. */ -export function findUsedLocals(expr: ExpressionRef, used: Set = new Set()): Set { +export function findUsedLocals(expr: ExpressionRef, used: Set = new Set()): Set { traverse(expr, used, findUsedLocalsVisit); return used; } diff --git a/src/module.ts b/src/module.ts index 0511cb04c7..acdc67ffe7 100644 --- a/src/module.ts +++ b/src/module.ts @@ -607,7 +607,6 @@ export class Module { offset: Index = 0, align: Index = bytes // naturally aligned by default ): ExpressionRef { - if (type < NativeType.None || type > NativeType.V128) throw new Error("here: " + type); return binaryen._BinaryenStore(this.ref, bytes, offset, align, ptr, value, type); } @@ -790,7 +789,7 @@ export class Module { for (let i = 0; i < numNames; ++i) { strs[i] = this.allocStringCached(names[i]); } - var cArr = allocI32Array(strs); + var cArr = allocPtrArray(strs); var cStr = this.allocStringCached(defaultName); var ret = binaryen._BinaryenSwitch(this.ref, cArr, numNames, cStr, condition, value); binaryen._free(cArr); @@ -806,8 +805,8 @@ export class Module { var cStr = this.allocStringCached(target); var cArr = allocPtrArray(operands); var ret = isReturn - ? binaryen._BinaryenReturnCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType) - : binaryen._BinaryenCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType); + ? binaryen._BinaryenReturnCall(this.ref, cStr, cArr, operands ? operands.length : 0, returnType) + : binaryen._BinaryenCall(this.ref, cStr, cArr, operands ? operands.length : 0, returnType); binaryen._free(cArr); return ret; } @@ -829,8 +828,8 @@ export class Module { ): ExpressionRef { var cArr = allocPtrArray(operands); var ret = isReturn - ? binaryen._BinaryenReturnCallIndirect(this.ref, index, cArr, operands && operands.length || 0, params, results) - : binaryen._BinaryenCallIndirect(this.ref, index, cArr, operands && operands.length || 0, params, results); + ? binaryen._BinaryenReturnCallIndirect(this.ref, index, cArr, operands ? operands.length : 0, params, results) + : binaryen._BinaryenCallIndirect(this.ref, index, cArr, operands ? operands.length : 0, params, results); binaryen._free(cArr); return ret; } @@ -1407,7 +1406,7 @@ export class Module { var func = this.addTemporaryFunction(type, null, expr); var names = this.cachedPrecomputeNames; if (!names) { - this.cachedPrecomputeNames = names = allocI32Array([ + this.cachedPrecomputeNames = names = allocPtrArray([ this.allocStringCached("vacuum"), this.allocStringCached("precompute") ]); @@ -1464,7 +1463,7 @@ export class Module { private cachedStrings: Map = new Map(); private allocStringCached(str: string | null): usize { - if (str == null) return 0; + if (str === null) return 0; var cachedStrings = this.cachedStrings; if (cachedStrings.has(str)) return cachedStrings.get(str); var ptr = allocString(str); @@ -1661,7 +1660,7 @@ export function getConstValueF32(expr: ExpressionRef): f32 { return binaryen._BinaryenConstGetValueF32(expr); } -export function getConstValueF64(expr: ExpressionRef): f32 { +export function getConstValueF64(expr: ExpressionRef): f64 { return binaryen._BinaryenConstGetValueF64(expr); } @@ -2041,7 +2040,7 @@ function stringLengthUTF8(str: string): usize { } function allocString(str: string | null): usize { - if (str == null) return 0; + if (str === null) return 0; var ptr = binaryen._malloc(stringLengthUTF8(str) + 1); // the following is based on Emscripten's stringToUTF8Array var idx = ptr; @@ -2168,7 +2167,7 @@ export function needsExplicitUnreachable(expr: ExpressionRef): bool { export function traverse(expr: ExpressionRef, data: T, visit: (expr: ExpressionRef, data: T) => void): bool { switch (getExpressionId(expr)) { case ExpressionId.Block: { - for (let i = 0, n = binaryen._BinaryenBlockGetNumChildren(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenBlockGetNumChildren(expr); i < n; ++i) { visit(binaryen._BinaryenBlockGetChild(expr, i), data); } break; @@ -2194,13 +2193,13 @@ export function traverse(expr: ExpressionRef, data: T, visit: (expr: Expressi break; } case ExpressionId.Call: { - for (let i = 0, n = binaryen._BinaryenCallGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenCallGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenCallGetOperand(expr, i), data); } break; } case ExpressionId.CallIndirect: { - for (let i = 0, n = binaryen._BinaryenCallIndirectGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenCallIndirectGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenCallIndirectGetOperand(expr, i), data); } break; @@ -2255,7 +2254,7 @@ export function traverse(expr: ExpressionRef, data: T, visit: (expr: Expressi break; } case ExpressionId.Host: { - for (let i = 0, n = binaryen._BinaryenHostGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenHostGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenHostGetOperand(expr, i), data); } break; @@ -2363,7 +2362,7 @@ export function traverse(expr: ExpressionRef, data: T, visit: (expr: Expressi break; } case ExpressionId.Throw: { - for (let i = 0, n = binaryen._BinaryenThrowGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenThrowGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenThrowGetOperand(expr, i), data); } break; diff --git a/src/parser.ts b/src/parser.ts index 8c6b7123a5..362cb7856c 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -787,8 +787,9 @@ export class Parser extends DiagnosticEmitter { return null; } this.tryParseSignatureIsSignature = true; + if (!parameters) parameters = []; return Node.createFunctionType( - parameters || [], + parameters, returnType, thisType, false, @@ -923,7 +924,7 @@ export class Parser extends DiagnosticEmitter { } } var range = Range.join(identifier.range, tn.range()); - if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && initializer) { + if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) != 0 && initializer !== null) { this.error( DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context, range); @@ -2048,7 +2049,7 @@ export class Parser extends DiagnosticEmitter { name.range ); } - if (parameters.length && parameters[0].initializer) { + if (parameters.length > 0 && parameters[0].initializer !== null) { this.error( DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, name.range @@ -2903,10 +2904,11 @@ export class Parser extends DiagnosticEmitter { let declarations = (initializer).declarations; for (let i = 0, k = declarations.length; i < k; ++i) { let declaration = declarations[i]; - if (declaration.initializer) { + let initializer = declaration.initializer; + if (initializer) { this.error( DiagnosticCode.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer, - declaration.initializer.range + initializer.range ); // recoverable } } diff --git a/src/program.ts b/src/program.ts index 8a507cb52c..7626070e3c 100644 --- a/src/program.ts +++ b/src/program.ts @@ -568,17 +568,19 @@ export class Program extends DiagnosticEmitter { flags: CommonFlags = CommonFlags.NONE ): FunctionDeclaration { var range = this.nativeSource.range; - return Node.createFunctionDeclaration( - Node.createIdentifierExpression(name, range), - null, - this.nativeDummySignature || (this.nativeDummySignature = Node.createFunctionType([], + var signature = this.nativeDummySignature; + if (!signature) { + this.nativeDummySignature = signature = Node.createFunctionType([], Node.createNamedType( // ^ AST signature doesn't really matter, is overridden anyway Node.createSimpleTypeName(CommonNames.void_, range), null, false, range ), - null, false, range) - ), - null, null, flags, ArrowKind.NONE, range + null, false, range + ); + } + return Node.createFunctionDeclaration( + Node.createIdentifierExpression(name, range), + null, signature, null, null, flags, ArrowKind.NONE, range ); } @@ -625,7 +627,7 @@ export class Program extends DiagnosticEmitter { getElementByDeclaration(declaration: DeclarationStatement): DeclaredElement | null { var elementsByDeclaration = this.elementsByDeclaration; return elementsByDeclaration.has(declaration) - ? elementsByDeclaration.get(declaration)! + ? assert(elementsByDeclaration.get(declaration)) : null; } @@ -2175,8 +2177,11 @@ export abstract class Element { /** Gets the enclosing file. */ get file(): File { var current: Element = this; - do if ((current = current.parent).kind == ElementKind.FILE) return current; - while (true); + do { + current = current.parent; + if (current.kind == ElementKind.FILE) return current; + } while (true); + return unreachable(); } /** Tests if this element has a specific flag or flags. */ @@ -2214,7 +2219,9 @@ export abstract class Element { if (merged) { element = merged; // use merged element } else { - let reportedIdentifier = localIdentifierIfImport || element.identifierNode; + let reportedIdentifier = localIdentifierIfImport + ? localIdentifierIfImport + : element.identifierNode; if (isDeclaredElement(existing.kind)) { this.program.errorRelated( DiagnosticCode.Duplicate_identifier_0, @@ -2244,7 +2251,7 @@ export abstract class Element { /** Returns a string representation of this element. */ toString(): string { - return ElementKind[this.kind] + ":" + this.internalName; + return this.internalName + ", kind=" + this.kind.toString(); } } @@ -2948,12 +2955,13 @@ export class Function extends TypedElement { var localName = name !== null ? name : "var$" + localIndex.toString(); + if (!declaration) declaration = this.program.makeNativeVariableDeclaration(localName); var local = new Local( localName, localIndex, type, this, - declaration || this.program.makeNativeVariableDeclaration(localName) + declaration ); if (name) { if (this.localsByName.has(name)) throw new Error("duplicate local name"); @@ -2967,7 +2975,7 @@ export class Function extends TypedElement { /* @override */ lookup(name: string): Element | null { var locals = this.localsByName; - if (locals.has(name)) return locals.get(name)!; + if (locals.has(name)) return assert(locals.get(name)); return this.parent.lookup(name); } @@ -3302,7 +3310,8 @@ export class ClassPrototype extends DeclaredElement { if (seen.has(current)) break; seen.add(current); if (current === basePtototype) return true; - } while (current = current.basePrototype); + current = current.basePrototype; + } while (current); return false; } @@ -3375,7 +3384,7 @@ export class Class extends TypedElement { /** Resolved type arguments. */ typeArguments: Type[] | null; /** Base class, if applicable. */ - base: Class | null; + base: Class | null = null; /** Contextual type arguments for fields and methods. */ contextualTypeArguments: Map | null = null; /** Current member memory offset. */ @@ -3497,8 +3506,10 @@ export class Class extends TypedElement { /** Tests if a value of this class type is assignable to a target of the specified class type. */ isAssignableTo(target: Class): bool { var current: Class | null = this; - do if (current == target) return true; - while (current = current.base); + do { + if (current == target) return true; + current = current.base; + } while (current); return false; } @@ -3526,7 +3537,8 @@ export class Class extends TypedElement { let overload = overloads.get(kind); if (overload) return overload; } - } while (instance = instance.base); + instance = instance.base; + } while (instance); return null; } diff --git a/src/resolver.ts b/src/resolver.ts index 5a527b9392..8bfda4dae5 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -255,7 +255,7 @@ export class Resolver extends DiagnosticEmitter { // Shortcut already resolved (mostly builtins) if (element.is(CommonFlags.RESOLVED)) { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -301,7 +301,7 @@ export class Resolver extends DiagnosticEmitter { reportMode ); if (!typeArguments) return null; - } else if (typeArgumentNodes && typeArgumentNodes.length) { + } else if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { this.error( DiagnosticCode.Type_0_is_not_generic, node.range, nameNode.identifier.text @@ -435,11 +435,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { if (reportMode == ReportMode.REPORT) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() + node.range, "1", numTypeArguments.toString() ); } return null; @@ -478,11 +480,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { if (reportMode == ReportMode.REPORT) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() + node.range, "1", numTypeArguments.toString() ); } return null; @@ -529,11 +533,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() + node.range, "1", numTypeArguments.toString() ); } return null; @@ -573,11 +579,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { if (reportMode == ReportMode.REPORT) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString() + node.range, "1", numTypeArguments.toString() ); } return null; @@ -766,7 +774,7 @@ export class Resolver extends DiagnosticEmitter { for (let i = 0; i < numTypeParameters; ++i) { let name = typeParameterNodes[i].name.text; if (contextualTypeArguments.has(name)) { - let inferredType = contextualTypeArguments.get(name)!; + let inferredType = assert(contextualTypeArguments.get(name)); if (inferredType != Type.auto) { resolvedTypeArguments[i] = inferredType; continue; @@ -809,7 +817,7 @@ export class Resolver extends DiagnosticEmitter { ): void { if (node.kind == NodeKind.NAMEDTYPE) { let typeArgumentNodes = (node).typeArguments; - if (typeArgumentNodes !== null && typeArgumentNodes.length) { // foo(bar: Array) + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { // foo(bar: Array) let classReference = type.classReference; if (classReference) { let classPrototype = this.resolveTypeName((node).name, ctxFlow.actualFunction); @@ -827,7 +835,7 @@ export class Resolver extends DiagnosticEmitter { } else { // foo(bar: T) let name = (node).name.identifier.text; if (ctxTypes.has(name)) { - let currentType = ctxTypes.get(name)!; + let currentType = assert(ctxTypes.get(name)); if (currentType == Type.auto || (typeParameterNames.has(name) && currentType.isAssignableTo(type))) { ctxTypes.set(name, type); } @@ -835,7 +843,7 @@ export class Resolver extends DiagnosticEmitter { } } else if (node.kind == NodeKind.FUNCTIONTYPE) { // foo(bar: (baz: T) => i32)) let parameterNodes = (node).parameters; - if (parameterNodes !== null && parameterNodes.length) { + if (parameterNodes !== null && parameterNodes.length > 0) { let signatureReference = type.signatureReference; if (signatureReference) { let parameterTypes = signatureReference.parameterTypes; @@ -883,7 +891,7 @@ export class Resolver extends DiagnosticEmitter { } else if (type != Type.void) { let wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(type)); - return wrapperClasses.get(type)!; + return assert(wrapperClasses.get(type)); } return null; } @@ -1209,7 +1217,7 @@ export class Resolver extends DiagnosticEmitter { var element = this.lookupIdentifierExpression(node, ctxFlow, ctxElement, reportMode); if (!element) return null; if (element.kind == ElementKind.FUNCTION_PROTOTYPE) { - let instance = this.resolveFunction(element, null, makeMap(), reportMode); + let instance = this.resolveFunction(element, null, makeMap(), reportMode); if (!instance) return null; element = instance; } @@ -1267,7 +1275,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(type)) { - classReference = wrapperClasses.get(type)!; + classReference = assert(wrapperClasses.get(type)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1294,7 +1302,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(type)) { - classReference = wrapperClasses.get(type)!; + classReference = assert(wrapperClasses.get(type)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1315,7 +1323,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(type)) { - classReference = wrapperClasses.get(type)!; + classReference = assert(wrapperClasses.get(type)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1348,7 +1356,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(returnType)) { - classReference = wrapperClasses.get(returnType)!; + classReference = assert(wrapperClasses.get(returnType)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1382,10 +1390,10 @@ export class Resolver extends DiagnosticEmitter { case ElementKind.CLASS: { do { let members = target.members; - if (members && members.has(propertyName)) { + if (members !== null && members.has(propertyName)) { this.currentThisExpression = targetNode; this.currentElementExpression = null; - return members.get(propertyName)!; // instance FIELD, static GLOBAL, FUNCTION_PROTOTYPE... + return assert(members.get(propertyName)); // instance FIELD, static GLOBAL, FUNCTION_PROTOTYPE... } // traverse inherited static members on the base prototype if target is a class prototype if (target.kind == ElementKind.CLASS_PROTOTYPE) { @@ -1409,10 +1417,10 @@ export class Resolver extends DiagnosticEmitter { } default: { // enums or other namespace-like elements let members = target.members; - if (members && members.has(propertyName)) { + if (members !== null && members.has(propertyName)) { this.currentThisExpression = targetNode; this.currentElementExpression = null; - return members.get(propertyName)!; // static ENUMVALUE, static GLOBAL, static FUNCTION_PROTOTYPE... + return assert(members.get(propertyName)); // static ENUMVALUE, static GLOBAL, static FUNCTION_PROTOTYPE... } break; } @@ -2156,10 +2164,13 @@ export class Resolver extends DiagnosticEmitter { } } var parent: Element | null = ctxFlow.actualFunction.parent; - if (parent && parent.kind == ElementKind.CLASS && (parent = (parent).base)) { - this.currentThisExpression = null; - this.currentElementExpression = null; - return parent; + if (parent !== null && parent.kind == ElementKind.CLASS) { + let base = (parent).base; + if (base) { + this.currentThisExpression = null; + this.currentElementExpression = null; + return parent; + } } if (reportMode == ReportMode.REPORT) { this.error( @@ -2216,13 +2227,13 @@ export class Resolver extends DiagnosticEmitter { ); let wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(intType)); - return wrapperClasses.get(intType)!; + return assert(wrapperClasses.get(intType)); } case LiteralKind.FLOAT: { let fltType = ctxType == Type.f32 ? Type.f32 : Type.f64; let wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(fltType)); - return wrapperClasses.get(fltType)!; + return assert(wrapperClasses.get(fltType)); } case LiteralKind.STRING: { return this.program.stringInstance; @@ -2420,7 +2431,7 @@ export class Resolver extends DiagnosticEmitter { ): Element | null { var wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(Type.bool)); - return wrapperClasses.get(Type.bool)!; + return assert(wrapperClasses.get(Type.bool)); } /** Resolves an instanceof expression to its static type. */ @@ -2705,7 +2716,7 @@ export class Resolver extends DiagnosticEmitter { if (prototype.is(CommonFlags.SET)) { returnType = Type.void; // not annotated } else if (prototype.is(CommonFlags.CONSTRUCTOR)) { - returnType = assert(classInstance).type; // not annotated + returnType = classInstance!.type; // not annotated } else { let typeNode = signatureNode.returnType; if (isTypeOmitted(typeNode)) { @@ -2795,7 +2806,7 @@ export class Resolver extends DiagnosticEmitter { // Otherwise make sure that no type arguments have been specified } else { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -3027,7 +3038,7 @@ export class Resolver extends DiagnosticEmitter { // Link _own_ constructor if present { let ctorPrototype = instance.lookupInSelf(CommonNames.constructor); - if (ctorPrototype && ctorPrototype.parent === instance) { + if (ctorPrototype !== null && ctorPrototype.parent === instance) { assert(ctorPrototype.kind == ElementKind.FUNCTION_PROTOTYPE); let ctorInstance = this.resolveFunction( ctorPrototype, @@ -3044,7 +3055,7 @@ export class Resolver extends DiagnosticEmitter { // for (let [overloadKind, overloadPrototype] of overloadPrototypes) { for (let _keys = Map_keys(overloadPrototypes), i = 0, k = _keys.length; i < k; ++i) { let overloadKind = unchecked(_keys[i]); - let overloadPrototype = overloadPrototypes.get(overloadKind)!; + let overloadPrototype = assert(overloadPrototypes.get(overloadKind)); assert(overloadKind != OperatorKind.INVALID); let operatorInstance: Function | null; if (overloadPrototype.is(CommonFlags.INSTANCE)) { diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 2f7b4584a0..ecbe23b028 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -479,7 +479,8 @@ export class Tokenizer extends DiagnosticEmitter { this.source = source; this.pos = 0; this.end = source.text.length; - this.diagnostics = diagnostics || new Array(); + if (!diagnostics) diagnostics = []; + this.diagnostics = diagnostics; var end = this.end; var text = source.text; @@ -1004,13 +1005,9 @@ export class Tokenizer extends DiagnosticEmitter { } mark(): State { - var state: State; - if (reusableState) { - state = reusableState; - reusableState = null; - } else { - state = new State(); - } + var state = reusableState; + if (state) reusableState = null; + else state = new State(); state.pos = this.pos; state.token = this.token; state.tokenPos = this.tokenPos; diff --git a/src/types.ts b/src/types.ts index 3bc5dab466..4afc65cee1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -108,7 +108,7 @@ export class Type { /** Type flags. */ flags: TypeFlags; /** Size in bits. */ - size: u32; + size: i32; /** Size in bytes. */ byteSize: i32; /** Underlying class reference, if a class type. */ @@ -180,12 +180,12 @@ export class Type { } /** Computes the sign-extending shift in the target type. */ - computeSmallIntegerShift(targetType: Type): u32 { + computeSmallIntegerShift(targetType: Type): i32 { return targetType.size - this.size; } /** Computes the truncating mask in the target type. */ - computeSmallIntegerMask(targetType: Type): u32 { + computeSmallIntegerMask(targetType: Type): i32 { var size = this.is(TypeFlags.UNSIGNED) ? this.size : this.size - 1; return ~0 >>> (targetType.size - size); } @@ -610,7 +610,7 @@ export class Signature { /** Gets the known or, alternatively, generic parameter name at the specified index. */ getParameterName(index: i32): string { var parameterNames = this.parameterNames; - return parameterNames && parameterNames.length > index + return parameterNames !== null && parameterNames.length > index ? parameterNames[index] : getDefaultParameterName(index); } @@ -627,8 +627,8 @@ export class Signature { // check `this` type var thisThisType = this.thisType; var targetThisType = value.thisType; - if (thisThisType) { - if (!(targetThisType && thisThisType.isAssignableTo(targetThisType))) return false; + if (thisThisType !== null) { + if (targetThisType === null || !thisThisType.isAssignableTo(targetThisType)) return false; } else if (targetThisType) { return false; } @@ -691,11 +691,10 @@ export class Signature { // helpers // Cached default parameter names used where names are unknown. -var cachedDefaultParameterNames: string[] | null = null; +var cachedDefaultParameterNames: string[] = []; /** Gets the cached default parameter name for the specified index. */ export function getDefaultParameterName(index: i32): string { - if (!cachedDefaultParameterNames) cachedDefaultParameterNames = []; for (let i = cachedDefaultParameterNames.length; i <= index; ++i) { cachedDefaultParameterNames.push("arg$" + i.toString()); } diff --git a/tests/compiler/loop-wrap.optimized.wat b/tests/compiler/loop-wrap.optimized.wat index be239915d9..0e348c49ae 100644 --- a/tests/compiler/loop-wrap.optimized.wat +++ b/tests/compiler/loop-wrap.optimized.wat @@ -25,21 +25,21 @@ ) (func $loop-wrap/testFirstWrapped (; 1 ;) (local $0 i32) - loop $while-continue|1 - local.get $0 - i32.const 1 - i32.add - local.tee $0 - i32.const 255 - i32.and - i32.const 0 + loop $do-continue|1 local.get $0 i32.const 255 i32.and i32.const 10 i32.ne - select - br_if $while-continue|1 + if + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 255 + i32.and + br_if $do-continue|1 + end end ) (func $loop-wrap/testSubsequentWrapped (; 2 ;) (param $0 i32) diff --git a/tests/compiler/loop-wrap.untouched.wat b/tests/compiler/loop-wrap.untouched.wat index e77f401ce4..5ef0e1dae7 100644 --- a/tests/compiler/loop-wrap.untouched.wat +++ b/tests/compiler/loop-wrap.untouched.wat @@ -37,8 +37,16 @@ (local $1 i32) i32.const 0 local.set $0 - block $while-break|1 - loop $while-continue|1 + block $do-break|1 + loop $do-continue|1 + local.get $0 + i32.const 255 + i32.and + i32.const 10 + i32.eq + if + br $do-break|1 + end local.get $0 i32.const 1 i32.add @@ -47,17 +55,7 @@ i32.and local.set $1 local.get $1 - if - local.get $0 - i32.const 255 - i32.and - i32.const 10 - i32.eq - if - br $while-break|1 - end - br $while-continue|1 - end + br_if $do-continue|1 end end ) diff --git a/tests/compiler/std/libm.untouched.wat b/tests/compiler/std/libm.untouched.wat index 6dae2603fd..8fa199dea0 100644 --- a/tests/compiler/std/libm.untouched.wat +++ b/tests/compiler/std/libm.untouched.wat @@ -1731,8 +1731,7 @@ if (result f64) global.get $~lib/math/NativeMath.PI else - i32.const 0 - f64.convert_i32_s + f64.const 0 end local.set $9 local.get $7 diff --git a/tests/compiler/std/math.untouched.wat b/tests/compiler/std/math.untouched.wat index 1d3bfff00f..baa0a69ddd 100644 --- a/tests/compiler/std/math.untouched.wat +++ b/tests/compiler/std/math.untouched.wat @@ -3427,8 +3427,7 @@ if (result f64) global.get $~lib/math/NativeMath.PI else - i32.const 0 - f64.convert_i32_s + f64.const 0 end local.set $9 local.get $7 diff --git a/tests/packages/packages/g/test.js b/tests/packages/packages/g/test.js index 880f92d597..ba9c641541 100644 --- a/tests/packages/packages/g/test.js +++ b/tests/packages/packages/g/test.js @@ -10,7 +10,7 @@ let argv = [ ]; asc.main(argv, error => { - if (/Import file .*lib\/a.ts.* not found/g.test(error.message)) { + if (/Import .*lib\/a.* not found/g.test(error.message)) { process.exit(0); } console.error("Failed!\n" + error); From 38016d697bf5288cf883132cb7d54b35264e8557 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 04:12:11 +0100 Subject: [PATCH 11/28] refactor hell part 5, down to 10 --- src/compiler.ts | 131 ++++++++++++++++++++++++++++++------------------ src/module.ts | 20 ++++---- src/parser.ts | 9 ++-- 3 files changed, 98 insertions(+), 62 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index fa0512a2ff..27f0404b8d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -2463,7 +2463,8 @@ export class Compiler extends DiagnosticEmitter { } else { thenStmts.push(this.compileStatement(ifTrue)); } - if (thenFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS)) { + var thenTerminates = thenFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS); + if (thenTerminates) { thenStmts.push(module.unreachable()); } else { this.performAutoreleases(thenFlow, thenStmts); @@ -2482,14 +2483,19 @@ export class Compiler extends DiagnosticEmitter { } else { elseStmts.push(this.compileStatement(ifFalse)); } - if (elseFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS)) { + let elseTerminates = elseFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS); + if (elseTerminates) { elseStmts.push(module.unreachable()); } else { this.performAutoreleases(elseFlow, elseStmts); } elseFlow.freeScopedLocals(); this.currentFlow = flow; - flow.inheritMutual(thenFlow, elseFlow); + if (elseTerminates && !thenTerminates) { + flow.inherit(thenFlow); + } else { + flow.inheritMutual(thenFlow, elseFlow); + } return module.if(condExpr, module.flatten(thenStmts), module.flatten(elseStmts) @@ -3749,15 +3755,17 @@ export class Compiler extends DiagnosticEmitter { commonType = Type.commonDenominator(leftType, rightType, true); if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4050,17 +4058,20 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4147,17 +4158,20 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4344,17 +4358,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4434,17 +4451,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4525,7 +4545,8 @@ export class Compiler extends DiagnosticEmitter { if (this.currentType.kind == TypeKind.F32) { rightExpr = this.compileExpression(right, Type.f32, Constraints.CONV_IMPLICIT); rightType = this.currentType; - if (!(instance = this.f32PowInstance)) { + instance = this.f32PowInstance; + if (!instance) { let namespace = this.program.lookupGlobal(CommonNames.Mathf); if (!namespace) { this.error( @@ -4559,7 +4580,8 @@ export class Compiler extends DiagnosticEmitter { leftType = this.currentType; rightExpr = this.compileExpression(right, Type.f64, Constraints.CONV_IMPLICIT); rightType = this.currentType; - if (!(instance = this.f64PowInstance)) { + instance = this.f64PowInstance; + if (!instance) { let namespace = this.program.lookupGlobal(CommonNames.Math); if (!namespace) { this.error( @@ -4622,17 +4644,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4731,17 +4756,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -5209,17 +5237,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -5302,17 +5333,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -6236,7 +6270,7 @@ export class Compiler extends DiagnosticEmitter { return this.compileCallExpressionBuiltin(prototype, expression, contextualType); } - let thisExpression = this.resolver.currentThisExpression; + let thisExpression = this.resolver.currentThisExpression; // compileCallDirect may reset let instance = this.resolver.maybeInferCall(expression, prototype, flow); if (!instance) return this.module.unreachable(); return this.compileCallDirect( @@ -6252,36 +6286,37 @@ export class Compiler extends DiagnosticEmitter { // indirect call: index argument with signature (non-generic, can't be inlined) case ElementKind.LOCAL: { - if (signature = (target).type.signatureReference) { + signature = (target).type.signatureReference; + if (signature) { if ((target).is(CommonFlags.INLINED)) { indexArg = module.i32(i64_low((target).constantIntegerValue)); } else { indexArg = module.local_get((target).index, NativeType.I32); } break; - } else { - this.error( - DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, (target).type.toString() - ); - return module.unreachable(); } + this.error( + DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, + expression.range, (target).type.toString() + ); + return module.unreachable(); } case ElementKind.GLOBAL: { - if (signature = (target).type.signatureReference) { + signature = (target).type.signatureReference; + if (signature) { indexArg = module.global_get((target).internalName, (target).type.toNativeType()); break; - } else { - this.error( - DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, (target).type.toString() - ); - return module.unreachable(); } + this.error( + DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, + expression.range, (target).type.toString() + ); + return module.unreachable(); } case ElementKind.FIELD: { let type = (target).type; - if (signature = type.signatureReference) { + signature = type.signatureReference; + if (signature) { let thisExpression = assert(this.resolver.currentThisExpression); let thisExpr = this.compileExpression(thisExpression, this.options.usizeType); indexArg = module.load( @@ -6355,7 +6390,7 @@ export class Compiler extends DiagnosticEmitter { } } return this.compileCallIndirect( - signature, + assert(signature), // FIXME: asc can't see this yet indexArg, expression.arguments, expression, diff --git a/src/module.ts b/src/module.ts index acdc67ffe7..c9f99964d4 100644 --- a/src/module.ts +++ b/src/module.ts @@ -2124,16 +2124,16 @@ export function readString(ptr: usize): string | null { } } arr.push(cp); - // if (cp < 0x10000) { - // arr.push(cp); - // } else { - // var ch = cp - 0x10000; - // arr.push(0xD800 | (ch >> 10)); - // arr.push(0xDC00 | (ch & 0x3FF)); - // } - } - // return String.fromCharCodes(arr); - return String.fromCodePoints(arr); + if (cp < 0x10000) { + arr.push(cp); + } else { + let ch = cp - 0x10000; + arr.push(0xD800 | (ch >> 10)); + arr.push(0xDC00 | (ch & 0x3FF)); + } + } + return String.fromCharCodes(arr); + // return String.fromCodePoints(arr); } /** Result structure of {@link Module#toBinary}. */ diff --git a/src/parser.ts b/src/parser.ts index 362cb7856c..5d71f29106 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -532,7 +532,7 @@ export class Parser extends DiagnosticEmitter { } else if (token == Token.IDENTIFIER) { let name = this.parseTypeName(tn); if (!name) return null; - let parameters: NamedTypeNode[] | null = null; + let parameters: TypeNode[] | null = null; let nullable = false; // Name @@ -540,8 +540,8 @@ export class Parser extends DiagnosticEmitter { do { let parameter = this.parseType(tn, true, suppressErrors); if (!parameter) return null; - if (!parameters) parameters = [parameter]; - else parameters.push(parameter); + if (!parameters) parameters = [ parameter ]; + else parameters.push(parameter); } while (tn.skip(Token.COMMA)); if (!tn.skip(Token.GREATERTHAN)) { if (!suppressErrors) { @@ -567,7 +567,8 @@ export class Parser extends DiagnosticEmitter { return null; } } - type = Node.createNamedType(name, parameters || [], nullable, tn.range(startPos, tn.pos)); + if (!parameters) parameters = []; + type = Node.createNamedType(name, parameters, nullable, tn.range(startPos, tn.pos)); } else { if (!suppressErrors) { this.error( From a56162a7e409f8dd617181ae770c6089efc74d7f Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 05:24:31 +0100 Subject: [PATCH 12/28] monkey-patch, down to 0 --- package.json | 4 +++- src/compiler.ts | 10 ++++++++-- src/parser.ts | 8 ++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 66ce0f03d6..e782e4071d 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,9 @@ "docs": "typedoc --tsconfig tsconfig-docs.json --mode modules --name \"AssemblyScript Compiler API\" --out ./docs/api --ignoreCompilerErrors --excludeNotExported --excludePrivate --excludeExternals --exclude **/std/** --includeDeclarations --readme src/README.md", "prepublishOnly": "node scripts/prepublish", "postpublish": "node scripts/postpublish", - "asbuild": "node bin/asc src/glue/wasm/index.ts src/index.ts" + "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", + "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm --validate --debug --measure", + "asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure" }, "releaseFiles": [ "lib/rtrace/index.d.ts", diff --git a/src/compiler.ts b/src/compiler.ts index 27f0404b8d..7e3c45cc03 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -634,12 +634,18 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.ENUMVALUE: { - if (!(element).isImmutable && !this.options.hasFeature(Feature.MUTABLE_GLOBALS)) { + let enumValue = element; + if (!enumValue.isImmutable && !this.options.hasFeature(Feature.MUTABLE_GLOBALS)) { this.error( DiagnosticCode.Cannot_export_a_mutable_global, - (element).identifierNode.range + enumValue.identifierNode.range ); } else { + if (enumValue.is(CommonFlags.INLINED)) { + let value = enumValue.constantIntegerValue; + assert(!i64_high(value)); + this.module.addGlobal(element.internalName, NativeType.I32, false, this.module.i32(i64_low(value))); + } this.module.addGlobalExport(element.internalName, prefix + name); } break; diff --git a/src/parser.ts b/src/parser.ts index 5d71f29106..3fc4dcc4e6 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1292,6 +1292,7 @@ export class Parser extends DiagnosticEmitter { if (!type) return null; } else { type = Node.createOmittedType(tn.range(tn.pos)); + type = type!; // FIXME: WHY? } let initializer: Expression | null = null; if (tn.skip(Token.EQUALS)) { @@ -1418,6 +1419,7 @@ export class Parser extends DiagnosticEmitter { returnType = Node.createOmittedType( tn.range(tn.pos) ); + returnType = returnType!; // FIXME: WHY? if (!isSetter) { this.error( DiagnosticCode.Type_expected, @@ -1526,6 +1528,7 @@ export class Parser extends DiagnosticEmitter { if (!returnType) return null; } else { returnType = Node.createOmittedType(tn.range(tn.pos)); + returnType = returnType!; // FIXME: WHY? } if (arrowKind) { @@ -2075,6 +2078,7 @@ export class Parser extends DiagnosticEmitter { if (!returnType) return null; } else { returnType = Node.createOmittedType(tn.range(tn.pos)); + returnType = returnType!; // FIXME: WHY? if (!isSetter && name.kind != NodeKind.CONSTRUCTOR) { this.error( DiagnosticCode.Type_expected, @@ -3535,6 +3539,7 @@ export class Parser extends DiagnosticEmitter { return null; } inner = Node.createParenthesizedExpression(inner, tn.range(startPos, tn.pos)); + inner = inner!; // FIXME: WHY? return this.maybeParseCallExpression(tn, inner); } // ArrayLiteralExpression @@ -3824,6 +3829,7 @@ export class Parser extends DiagnosticEmitter { null, tn.range(startPos, tn.pos) ); + expr = expr!; // FIXME: WHY? expr = this.maybeParseCallExpression(tn, expr); break; } @@ -3854,6 +3860,7 @@ export class Parser extends DiagnosticEmitter { next, tn.range(startPos, tn.pos) ); + expr = expr!; // FIXME: WHY? expr = this.maybeParseCallExpression(tn, expr); break; } @@ -3921,6 +3928,7 @@ export class Parser extends DiagnosticEmitter { next, tn.range(startPos, tn.pos) ); + expr = expr!; // FIXME: WHY? } else { let next = this.parseExpression(tn, nextPrecedence + 1); if (!next) return null; From 297671d463ca660a40c1b662273e9707a6a3b07c Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 07:26:57 +0100 Subject: [PATCH 13/28] proper missing enum module exports fix --- src/compiler.ts | 23 ++++++++++------------- src/program.ts | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 7e3c45cc03..7b4f9947d7 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -560,18 +560,20 @@ export class Compiler extends DiagnosticEmitter { /** Applies the respective module exports for the specified file. */ private ensureModuleExports(file: File): void { - var members = file.exports; - if (members) { - // for (let [memberName, member] of members) { - for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { - let memberName = unchecked(_keys[i]); - let member = assert(members.get(memberName)); - this.ensureModuleExport(memberName, member); + var exports = file.exports; + if (exports) { + // for (let [elementName, element] of exports) { + for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { + let elementName = unchecked(_keys[i]); + let element = assert(exports.get(elementName)); + this.ensureModuleExport(elementName, element); } } var exportsStar = file.exportsStar; if (exportsStar) { - for (let i = 0, k = exportsStar.length; i < k; ++i) this.ensureModuleExports(exportsStar[i]); + for (let i = 0, k = exportsStar.length; i < k; ++i) { + this.ensureModuleExports(exportsStar[i]); + } } } @@ -641,11 +643,6 @@ export class Compiler extends DiagnosticEmitter { enumValue.identifierNode.range ); } else { - if (enumValue.is(CommonFlags.INLINED)) { - let value = enumValue.constantIntegerValue; - assert(!i64_high(value)); - this.module.addGlobal(element.internalName, NativeType.I32, false, this.module.i32(i64_low(value))); - } this.module.addGlobalExport(element.internalName, prefix + name); } break; diff --git a/src/program.ts b/src/program.ts index 7626070e3c..b9dc70857d 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1003,12 +1003,8 @@ export class Program extends DiagnosticEmitter { // for (let file of this.filesByName.values()) { for (let _values = Map_values(this.filesByName), i = 0, k = _values.length; i < k; ++i) { let file = unchecked(_values[i]); - let exports = file.exports; - if (exports !== null && file.source.sourceKind == SourceKind.USER_ENTRY) { - for (let _values = Map_values(exports), j = 0, l = _values.length; j < l; ++j) { - let element = unchecked(_values[j]); - this.markModuleExport(element); - } + if (file.source.sourceKind == SourceKind.USER_ENTRY) { + this.markModuleExports(file); } } } @@ -1044,6 +1040,24 @@ export class Program extends DiagnosticEmitter { return resolved; } + /** Marks all exports of the specified file as module exports. */ + private markModuleExports(file: File): void { + var exports = file.exports; + if (exports) { + // for (let element of exports.values()) { + for (let _values = Map_values(exports), j = 0, l = _values.length; j < l; ++j) { + let element = unchecked(_values[j]); + this.markModuleExport(element); + } + } + var exportsStar = file.exportsStar; + if (exportsStar) { + for (let i = 0, k = exportsStar.length; i < k; ++i) { + this.markModuleExports(exportsStar[i]); + } + } + } + /** Marks an element and its children as a module export. */ private markModuleExport(element: Element): void { element.set(CommonFlags.MODULE_EXPORT); @@ -1071,14 +1085,12 @@ export class Program extends DiagnosticEmitter { case ElementKind.FIELD: case ElementKind.CLASS: assert(false); // assumes that there are no instances yet } - { - let staticMembers = element.members; - if (staticMembers) { - // for (let member of staticMembers.values()) { - for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { - let member = unchecked(_values[i]); - this.markModuleExport(member); - } + var staticMembers = element.members; + if (staticMembers) { + // for (let member of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.markModuleExport(member); } } } From ae30958288cab76905c4b59335e481b60eff2a87 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 07:27:11 +0100 Subject: [PATCH 14/28] add self-test to CI --- .github/workflows/ci.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 188f6fb6f0..1cc648ae32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,3 +141,18 @@ jobs: cd lib/loader npm run asbuild npm run test + test-bootstrap: + name: "Test self-compilation on node: node" + runs-on: ubuntu-latest + needs: check + steps: + - uses: actions/checkout@v1.0.0 + - uses: dcodeIO/setup-node-nvm@v1.0.0 + with: + node-version: node + - name: Install dependencies + run: npm ci --no-audit + - name: Clean distribution files + run: npm run clean + - name: Test self-compilation + run: npm run asbuild From a85dbebf11605287eec620a2ba47c4fd8010dafb Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 08:07:52 +0100 Subject: [PATCH 15/28] remove parseFloat import / use strtod --- src/tokenizer.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tokenizer.ts b/src/tokenizer.ts index ecbe23b028..fda08e1b52 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -451,8 +451,6 @@ export class Range { debugInfoRef: usize = 0; } -declare function parseFloat(str: string): f64; - /** Handler for intercepting comments while tokenizing. */ export type CommentHandler = (kind: CommentKind, text: string, range: Range) => void; From ecd04c6cf0e1ea7dae651d1c673ebb8158fb18bb Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 08:42:13 +0100 Subject: [PATCH 16/28] fix binaryen binding, initial instantiate test --- .github/workflows/ci.yml | 4 +++- src/glue/binaryen.d.ts | 7 +++---- src/index.ts | 3 ++- src/module.ts | 14 +++++--------- tests/boostrap/index.js | 23 +++++++++++++++++++++++ 5 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 tests/boostrap/index.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cc648ae32..1e04813eae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,4 +155,6 @@ jobs: - name: Clean distribution files run: npm run clean - name: Test self-compilation - run: npm run asbuild + run: | + npm run asbuild + node tests/bootstrap diff --git a/src/glue/binaryen.d.ts b/src/glue/binaryen.d.ts index 32d72ffef2..547b31e95b 100644 --- a/src/glue/binaryen.d.ts +++ b/src/glue/binaryen.d.ts @@ -725,7 +725,7 @@ export declare function _BinaryenRemoveGlobal(module: BinaryenModuleRef, name: u export declare function _BinaryenGlobalGetName(global: BinaryenGlobalRef): usize; export declare function _BinaryenGlobalGetType(global: BinaryenGlobalRef): BinaryenType; export declare function _BinaryenGlobalIsMutable(global: BinaryenGlobalRef): bool; -export declare function _BinaryenGlobalGetInit(global: BinaryenGlobalRef): BinaryenExpressionRef; +export declare function _BinaryenGlobalGetInitExpr(global: BinaryenGlobalRef): BinaryenExpressionRef; type BinaryenEventRef = usize; @@ -735,9 +735,8 @@ export declare function _BinaryenRemoveEvent(module: BinaryenModuleRef, name: us export declare function _BinaryenEventGetName(event: BinaryenEventRef): usize; export declare function _BinaryenEventGetAttribute(event: BinaryenEventRef): u32; -export declare function _BinaryenEventGetType(event: BinaryenEventRef): usize; -export declare function _BinaryenEventGetNumParams(event: BinaryenEventRef): BinaryenIndex; -export declare function _BinaryenEventGetParam(event: BinaryenEventRef, index: BinaryenIndex): BinaryenType; +export declare function _BinaryenEventGetParams(event: BinaryenEventRef): BinaryenType; +export declare function _BinaryenEventGetResults(event: BinaryenEventRef): BinaryenType; export declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, initial: BinaryenIndex, maximum: BinaryenIndex, funcs: usize, numFuncs: BinaryenIndex, offset: BinaryenExpressionRef): void; diff --git a/src/index.ts b/src/index.ts index 4f2ce40e18..338f81efcc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -245,4 +245,5 @@ export * from "./program"; export * from "./resolver"; export * from "./tokenizer"; export * from "./types"; -export * from "./util/index"; +import * as util from "./util/index"; +export { util }; diff --git a/src/module.ts b/src/module.ts index c9f99964d4..fa47ab3dde 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1867,7 +1867,7 @@ export function isGlobalMutable(global: GlobalRef): bool { } export function getGlobalInit(global: GlobalRef): ExpressionRef { - return binaryen._BinaryenGlobalGetInit(global); + return binaryen._BinaryenGlobalGetInitExpr(global); } // events @@ -1880,16 +1880,12 @@ export function getEventAttribute(event: EventRef): u32 { return binaryen._BinaryenEventGetAttribute(event); } -export function getEventType(event: EventRef): string | null { - return readString(binaryen._BinaryenEventGetType(event)); +export function getEventParams(event: EventRef): NativeType { + return binaryen._BinaryenEventGetParams(event); } -export function getEventParamCount(event: EventRef): Index { - return binaryen._BinaryenEventGetNumParams(event); -} - -export function getEventParam(event: EventRef, index: Index): NativeType { - return binaryen._BinaryenEventGetParam(event, index); +export function getEventResults(event: EventRef): NativeType { + return binaryen._BinaryenEventGetResults(event); } export class Relooper { diff --git a/tests/boostrap/index.js b/tests/boostrap/index.js new file mode 100644 index 0000000000..ea6336f146 --- /dev/null +++ b/tests/boostrap/index.js @@ -0,0 +1,23 @@ +const fs = require("fs"); +const binaryen = require("binaryen"); +const loader = require("../../lib/loader"); + +async function test(build) { + await binaryen.ready; + const assemblyscript = await loader.instantiate(fs.promises.readFile(__dirname + "/../../out/assemblyscript." + build + ".wasm"), { binaryen }); + console.log(assemblyscript); + const optionsPtr = assemblyscript.newOptions(); + const programPtr = assemblyscript.newProgram(optionsPtr); + const textPtr = assemblyscript.__allocString("export function add(a: i32, b: i32): i32 { return a + b; }\n"); + const pathPtr = assemblyscript.__allocString("index.ts"); + assemblyscript.parse(programPtr, textPtr, pathPtr, true); + var nextFilePtr = assemblyscript.nextFile(programPtr); + while (nextFilePtr) { + console.log("nextFile: " + assemblyscript.__getString(nextFilePtr)); + nextFilePtr = assemblyscript.nextFile(programPtr); + } + // assemblyscript.compile(programPtr); + // ^ fails, most likely due to confused virtual overloads + console.log("So far, so good."); +} +test("untouched"); From ae7e28eb15c1a1bdf4f91d6959e47c84aeb2f380 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 08:45:18 +0100 Subject: [PATCH 17/28] boostrap eh --- tests/{boostrap => bootstrap}/index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{boostrap => bootstrap}/index.js (100%) diff --git a/tests/boostrap/index.js b/tests/bootstrap/index.js similarity index 100% rename from tests/boostrap/index.js rename to tests/bootstrap/index.js From 2e874eddeda238a57cfeb7ea04240a1c075692f5 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 09:07:52 +0100 Subject: [PATCH 18/28] fix resolving super --- src/resolver.ts | 2 +- tests/bootstrap/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resolver.ts b/src/resolver.ts index 8bfda4dae5..6e9799f562 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2169,7 +2169,7 @@ export class Resolver extends DiagnosticEmitter { if (base) { this.currentThisExpression = null; this.currentElementExpression = null; - return parent; + return base; } } if (reportMode == ReportMode.REPORT) { diff --git a/tests/bootstrap/index.js b/tests/bootstrap/index.js index ea6336f146..7e4e89fbe7 100644 --- a/tests/bootstrap/index.js +++ b/tests/bootstrap/index.js @@ -17,7 +17,7 @@ async function test(build) { nextFilePtr = assemblyscript.nextFile(programPtr); } // assemblyscript.compile(programPtr); - // ^ fails, most likely due to confused virtual overloads + // ^ abort: missing ArrayBuffer at src/program.ts:1015:18 console.log("So far, so good."); } test("untouched"); From 7b4ea5586a9e307cd2d3d4dc4e936f3855452a50 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 19:11:30 +0100 Subject: [PATCH 19/28] warn on virtual calls, make a working d.ts --- .github/workflows/ci.yml | 2 +- package.json | 2 +- src/compiler.ts | 54 +++++++++++++++++++++++--- src/definitions.ts | 43 +++++++++++++------- src/diagnosticMessages.generated.ts | 2 + src/diagnosticMessages.json | 1 + src/program.ts | 26 +++++++++++++ tests/bootstrap/{index.js => index.ts} | 11 +++--- 8 files changed, 116 insertions(+), 25 deletions(-) rename tests/bootstrap/{index.js => index.ts} (66%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e04813eae..1279b65e59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -157,4 +157,4 @@ jobs: - name: Test self-compilation run: | npm run asbuild - node tests/bootstrap + ts-node tests/bootstrap diff --git a/package.json b/package.json index e782e4071d..1ec0df2231 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "prepublishOnly": "node scripts/prepublish", "postpublish": "node scripts/postpublish", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", - "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm --validate --debug --measure", + "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.untouched.d.ts --validate --debug --measure", "asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure" }, "releaseFiles": [ diff --git a/src/compiler.ts b/src/compiler.ts index 7b4f9947d7..1c2d526da0 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -343,6 +343,8 @@ export class Compiler extends DiagnosticEmitter { lazyLibraryFunctions: Set = new Set(); /** Pending class-specific instanceof helpers. */ pendingClassInstanceOf: Set = new Set(); + /** Functions potentially involving a virtual call. */ + virtualCalls: Set = new Set(); /** Compiles a {@link Program} to a {@link Module} using the specified options. */ static compile(program: Program): Module { @@ -476,6 +478,9 @@ export class Compiler extends DiagnosticEmitter { compileClassInstanceOf(this, prototype); } + // set up virtual lookup tables + this.setupVirtualLookupTables(); + // finalize runtime features module.removeGlobal(BuiltinNames.rtti_base); if (this.runtimeFeatures & RuntimeFeatures.RTTI) compileRTTI(this); @@ -556,6 +561,36 @@ export class Compiler extends DiagnosticEmitter { return module; } + private setupVirtualLookupTables(): void { + // TODO: :-) + var program = this.program; + var virtualCalls = this.virtualCalls; + + // Virtual instance methods in the function table are potentially called virtually + var functionTable = this.functionTable; + var elementsByName = program.elementsByName; + for (let i = 0, k = functionTable.length; i < k; ++i) { + let instanceName = unchecked(functionTable[i]); + if(elementsByName.has(instanceName)) { // otherwise ~anonymous + let instance = assert(elementsByName.get(instanceName)); + if (instance.is(CommonFlags.INSTANCE | CommonFlags.VIRTUAL)) { + assert(instance.kind == ElementKind.FUNCTION); + virtualCalls.add(instance); + } + } + } + + // Inject a virtual lookup table into each function potentially called virtually + /// for (let instance of virtualCalls.values()) { + for (let _values = Set_values(virtualCalls), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); + this.warning( + DiagnosticCode.Function_0_is_possibly_called_virtually_which_is_not_yet_supported, + instance.identifierNode.range, instance.internalName + ); + } + } + // === Exports ================================================================================== /** Applies the respective module exports for the specified file. */ @@ -1262,12 +1297,16 @@ export class Compiler extends DiagnosticEmitter { this.currentFlow = previousFlow; // create the function + let body = module.flatten(stmts, instance.signature.returnType.toNativeType()); + if (instance.is(CommonFlags.VIRTUAL)) { + body = module.block("vtable", [ body ], getExpressionType(body)); + } funcRef = module.addFunction( instance.internalName, signature.nativeParams, signature.nativeResults, typesToNativeTypes(instance.additionalLocals), - module.flatten(stmts, instance.signature.returnType.toNativeType()) + body ); // imported function @@ -6211,8 +6250,10 @@ export class Compiler extends DiagnosticEmitter { return module.unreachable(); } - let classInstance = assert(actualFunction.parent); assert(classInstance.kind == ElementKind.CLASS); - let baseClassInstance = assert((classInstance).base); + let parent = assert(actualFunction.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; + let baseClassInstance = assert(classInstance.base); let thisLocal = assert(flow.lookupLocal(CommonNames.this_)); let nativeSizeType = this.options.nativeSizeType; @@ -6229,7 +6270,7 @@ export class Compiler extends DiagnosticEmitter { module.local_get(thisLocal.index, nativeSizeType), module.local_get(thisLocal.index, nativeSizeType), this.makeRetain( - this.makeAllocation(classInstance) + this.makeAllocation(classInstance) ) ), Constraints.WILL_RETAIN @@ -6238,7 +6279,7 @@ export class Compiler extends DiagnosticEmitter { let stmts: ExpressionRef[] = [ module.local_set(thisLocal.index, theCall) ]; - this.makeFieldInitializationInConstructor(classInstance, stmts); + this.makeFieldInitializationInConstructor(classInstance, stmts); // check that super had been called before accessing `this` if (flow.isAny( @@ -7169,6 +7210,9 @@ export class Compiler extends DiagnosticEmitter { /** Skip the usual autorelease and manage this at the callsite instead. */ skipAutorelease: bool = false ): ExpressionRef { + if (instance.is(CommonFlags.VIRTUAL)) { + this.virtualCalls.add(instance); + } if (instance.hasDecorator(DecoratorFlags.INLINE)) { assert(!instance.is(CommonFlags.TRAMPOLINE)); // doesn't make sense let inlineStack = this.inlineStack; diff --git a/src/definitions.ts b/src/definitions.ts index ac1a31cdb0..e5fa37dacc 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -89,7 +89,7 @@ export abstract class ExportsWalker { visitElement(name: string, element: Element): void { if (element.is(CommonFlags.PRIVATE) && !this.includePrivate) return; var seen = this.seen; - if (seen.has(element)) { + if (seen.has(element) && !element.is(CommonFlags.INSTANCE)) { this.visitAlias(name, element, seen.get(element)); return; } @@ -103,6 +103,7 @@ export abstract class ExportsWalker { if (element.is(CommonFlags.COMPILED)) this.visitEnum(name, element); break; } + case ElementKind.ENUMVALUE: break; // handled by visitEnum case ElementKind.FUNCTION_PROTOTYPE: { this.visitFunctionInstances(name, element); break; @@ -412,8 +413,9 @@ export class TSDBuilder extends ExportsWalker { sb.push(name); sb.push(" {\n"); var members = element.members; + var remainingMembers = 0; if (members) { - let remainingMembers = members.size; + remainingMembers = members.size; // for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); @@ -431,10 +433,10 @@ export class TSDBuilder extends ExportsWalker { --remainingMembers; } } - if (remainingMembers) this.visitNamespace(name, element); } indent(sb, --this.indentLevel); sb.push("}\n"); + if (remainingMembers) this.visitNamespace(name, element); } visitFunction(name: string, element: Function): void { @@ -483,15 +485,17 @@ export class TSDBuilder extends ExportsWalker { if (isInterface) { sb.push("export interface "); } else { + sb.push("export "); if (element.is(CommonFlags.ABSTRACT)) sb.push("abstract "); - sb.push("export class "); + sb.push("class "); } sb.push(name); - // var base = element.base; - // if (base && base.is(CommonFlags.COMPILED | CommonFlags.MODULE_EXPORT)) { - // sb.push(" extends "); - // sb.push(base.name); // TODO: fqn - // } + var base = element.base; + if (base !== null && base.is(CommonFlags.COMPILED | CommonFlags.MODULE_EXPORT)) { + sb.push(" extends "); + let extendsNode = assert(element.prototype.extendsNode); + sb.push(extendsNode.name.identifier.text); // TODO: fqn? + } sb.push(" {\n"); var staticMembers = element.prototype.members; if (staticMembers) { @@ -563,14 +567,14 @@ export class TSDBuilder extends ExportsWalker { case TypeKind.I8: return "i8"; case TypeKind.I16: return "i16"; case TypeKind.I32: return "i32"; - case TypeKind.I64: return "I64"; - case TypeKind.ISIZE: return this.program.options.isWasm64 ? "I64" : "i32"; + case TypeKind.I64: return "i64"; + case TypeKind.ISIZE: return "isize"; case TypeKind.U8: return "u8"; case TypeKind.U16: return "u16"; case TypeKind.U32: return "u32"; // ^ TODO: function types - case TypeKind.U64: return "U64"; - case TypeKind.USIZE: return this.program.options.isWasm64 ? "U64" : "u32"; + case TypeKind.U64: return "u64"; + case TypeKind.USIZE: return "usize"; // ^ TODO: class types case TypeKind.BOOL: return "bool"; case TypeKind.F32: return "f32"; @@ -586,13 +590,26 @@ export class TSDBuilder extends ExportsWalker { build(): string { var sb = this.sb; + var isWasm64 = this.program.options.isWasm64; sb.push("declare module ASModule {\n"); sb.push(" type i8 = number;\n"); sb.push(" type i16 = number;\n"); sb.push(" type i32 = number;\n"); + sb.push(" type i64 = BigInt;\n"); + if (isWasm64) { + sb.push(" type isize = BigInt;\n"); + } else { + sb.push(" type isize = number;\n"); + } sb.push(" type u8 = number;\n"); sb.push(" type u16 = number;\n"); sb.push(" type u32 = number;\n"); + sb.push(" type u64 = BigInt;\n"); + if (isWasm64) { + sb.push(" type usize = BigInt;\n"); + } else { + sb.push(" type usize = number;\n"); + } sb.push(" type f32 = number;\n"); sb.push(" type f64 = number;\n"); sb.push(" type bool = any;\n"); diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index eeb904ee1b..a6de0f5569 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -11,6 +11,7 @@ export enum DiagnosticCode { Operation_is_unsafe = 101, User_defined_0 = 102, Feature_0_is_not_enabled = 103, + Function_0_is_possibly_called_virtually_which_is_not_yet_supported = 104, Conversion_from_type_0_to_1_requires_an_explicit_cast = 200, Conversion_from_type_0_to_1_will_require_an_explicit_cast_when_switching_between_32_64_bit = 201, Type_0_cannot_be_changed_to_type_1 = 202, @@ -163,6 +164,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 101: return "Operation is unsafe."; case 102: return "User-defined: {0}"; case 103: return "Feature '{0}' is not enabled."; + case 104: return "Function '{0}' is possibly called virtually, which is not yet supported."; case 200: return "Conversion from type '{0}' to '{1}' requires an explicit cast."; case 201: return "Conversion from type '{0}' to '{1}' will require an explicit cast when switching between 32/64-bit."; case 202: return "Type '{0}' cannot be changed to type '{1}'."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index bb71ba653c..049e89ceb4 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -3,6 +3,7 @@ "Operation is unsafe.": 101, "User-defined: {0}": 102, "Feature '{0}' is not enabled.": 103, + "Function '{0}' is possibly called virtually, which is not yet supported.": 104, "Conversion from type '{0}' to '{1}' requires an explicit cast.": 200, "Conversion from type '{0}' to '{1}' will require an explicit cast when switching between 32/64-bit.": 201, diff --git a/src/program.ts b/src/program.ts index b9dc70857d..67415915cb 100644 --- a/src/program.ts +++ b/src/program.ts @@ -3270,6 +3270,8 @@ export class ClassPrototype extends DeclaredElement { overloadPrototypes: Map = new Map(); /** Already resolved instances. */ instances: Map | null = null; + /** Classes extending this class. */ + extendees: Set = new Set(); constructor( /** Simple name. */ @@ -3497,6 +3499,30 @@ export class Class extends TypedElement { assert(!this.base); this.base = base; + // Remember extendees and mark overloaded methods virtual + var basePrototype: ClassPrototype = base.prototype; + var thisPrototype = this.prototype; + assert(basePrototype != thisPrototype); + basePrototype.extendees.add(thisPrototype); + var thisInstanceMembers = thisPrototype.instanceMembers; + if (thisInstanceMembers) { + do { + let baseInstanceMembers = basePrototype.instanceMembers; + if (baseInstanceMembers) { + for (let _keys = Map_keys(baseInstanceMembers), i = 0, k = _keys.length; i < k; ++i) { + let memberName = _keys[i]; + let member = assert(baseInstanceMembers.get(memberName)); + if (thisInstanceMembers.has(memberName)) { + member.set(CommonFlags.VIRTUAL); + } + } + } + let nextPrototype = basePrototype.basePrototype; + if (!nextPrototype) break; + basePrototype = nextPrototype; + } while (true); + } + // Inherit contextual type arguments from base class var inheritedTypeArguments = base.contextualTypeArguments; if (inheritedTypeArguments) { diff --git a/tests/bootstrap/index.js b/tests/bootstrap/index.ts similarity index 66% rename from tests/bootstrap/index.js rename to tests/bootstrap/index.ts index 7e4e89fbe7..673bc0a358 100644 --- a/tests/bootstrap/index.js +++ b/tests/bootstrap/index.ts @@ -1,10 +1,11 @@ -const fs = require("fs"); -const binaryen = require("binaryen"); -const loader = require("../../lib/loader"); +import * as fs from "fs"; +import * as binaryen from "binaryen"; +import * as loader from "../../lib/loader"; +import AssemblyScript from "../../out/assemblyscript"; -async function test(build) { +async function test(build: string): Promise { await binaryen.ready; - const assemblyscript = await loader.instantiate(fs.promises.readFile(__dirname + "/../../out/assemblyscript." + build + ".wasm"), { binaryen }); + const assemblyscript = await loader.instantiate(fs.promises.readFile(__dirname + "/../../out/assemblyscript." + build + ".wasm"), { binaryen }); console.log(assemblyscript); const optionsPtr = assemblyscript.newOptions(); const programPtr = assemblyscript.newProgram(optionsPtr); From 7d795a0e25aaf9f4bb8f8049e135f24d07ef3cf1 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 19:13:28 +0100 Subject: [PATCH 20/28] lint --- src/compiler.ts | 2 +- src/program.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 1c2d526da0..dbe09b293d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -571,7 +571,7 @@ export class Compiler extends DiagnosticEmitter { var elementsByName = program.elementsByName; for (let i = 0, k = functionTable.length; i < k; ++i) { let instanceName = unchecked(functionTable[i]); - if(elementsByName.has(instanceName)) { // otherwise ~anonymous + if (elementsByName.has(instanceName)) { // otherwise ~anonymous let instance = assert(elementsByName.get(instanceName)); if (instance.is(CommonFlags.INSTANCE | CommonFlags.VIRTUAL)) { assert(instance.kind == ElementKind.FUNCTION); diff --git a/src/program.ts b/src/program.ts index 67415915cb..c7990f8506 100644 --- a/src/program.ts +++ b/src/program.ts @@ -2215,7 +2215,7 @@ export abstract class Element { } /** Looks up the element with the specified name relative to this element, like in JS. */ - /* abstract */ lookup(name: string): Element | null { return unreachable(); } + /* abstract */ lookup(name: string): Element | null { return unreachable(); } /** Adds an element as a member of this one. Reports and returns `false` if a duplicate. */ add(name: string, element: DeclaredElement, localIdentifierIfImport: IdentifierExpression | null = null): bool { From 246f324e66aa9578593125a2e2be8325c58f3252 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 19:18:23 +0100 Subject: [PATCH 21/28] go home npm, you're drunk --- .github/workflows/ci.yml | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1279b65e59..ba171dbd43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -157,4 +157,4 @@ jobs: - name: Test self-compilation run: | npm run asbuild - ts-node tests/bootstrap + npm run astest diff --git a/package.json b/package.json index 1ec0df2231..5b1c3f6ab4 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,8 @@ "postpublish": "node scripts/postpublish", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.untouched.d.ts --validate --debug --measure", - "asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure" + "asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure", + "astest": "ts-node tests/bootstrap" }, "releaseFiles": [ "lib/rtrace/index.d.ts", From fb6215410cae7b3d524519df9c5ad8d2e61204a4 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 1 Mar 2020 19:23:17 +0100 Subject: [PATCH 22/28] cheers --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b1c3f6ab4..fea8b37574 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "prepublishOnly": "node scripts/prepublish", "postpublish": "node scripts/postpublish", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", - "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.untouched.d.ts --validate --debug --measure", + "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.d.ts --validate --debug --measure", "asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure", "astest": "ts-node tests/bootstrap" }, From 642c3904b0f4e85cc3f02c5c092dc92e6bc5a626 Mon Sep 17 00:00:00 2001 From: dcode Date: Mon, 2 Mar 2020 03:44:33 +0100 Subject: [PATCH 23/28] fix rogue diagnostic on varargs calls --- src/compiler.ts | 5 ++++- src/program.ts | 2 +- src/resolver.ts | 24 +++++++++++++----------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index dbe09b293d..579622c9a5 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -6653,6 +6653,9 @@ export class Compiler extends DiagnosticEmitter { thisArg: ExpressionRef = 0, immediatelyDropped: bool = false ): ExpressionRef { + if (instance.is(CommonFlags.VIRTUAL)) { + this.virtualCalls.add(instance); + } var module = this.module; var numArguments = operands ? operands.length : 0; var signature = instance.signature; @@ -7282,7 +7285,7 @@ export class Compiler extends DiagnosticEmitter { )); continue; } - let resolved = this.resolver.lookupExpression(initializer, instance.flow, parameterTypes[i]); + let resolved = this.resolver.lookupExpression(initializer, instance.flow, parameterTypes[i], ReportMode.SWALLOW); if (resolved) { if (resolved.kind == ElementKind.GLOBAL) { let global = resolved; diff --git a/src/program.ts b/src/program.ts index c7990f8506..cf3b38ecb3 100644 --- a/src/program.ts +++ b/src/program.ts @@ -3689,7 +3689,7 @@ export class Class extends TypedElement { } /** Tests if this class potentially forms a reference cycle to another one. */ - private cyclesTo(other: Class, except: Set = new Set()): bool { + private cyclesTo(other: Class, except: Set = new Set()): bool { // TODO: The pure RC paper describes acyclic data structures as classes that may contain // // - scalars diff --git a/src/resolver.ts b/src/resolver.ts index 6e9799f562..cb657ae5fd 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -665,17 +665,19 @@ export class Resolver extends DiagnosticEmitter { } var argumentCount = typeArgumentNodes ? typeArgumentNodes.length : 0; if (argumentCount < minParameterCount || argumentCount > maxParameterCount) { - this.error( - DiagnosticCode.Expected_0_type_arguments_but_got_1, - argumentCount - ? Range.join( - typeArgumentNodes![0].range, - typeArgumentNodes![argumentCount - 1].range - ) - : alternativeReportNode!.range, - (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(), - argumentCount.toString() - ); + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + argumentCount + ? Range.join( + typeArgumentNodes![0].range, + typeArgumentNodes![argumentCount - 1].range + ) + : alternativeReportNode!.range, + (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(), + argumentCount.toString() + ); + } return null; } var typeArguments = new Array(maxParameterCount); From 44568f99f9e39a92554c8eb3da3fa949bfa1251d Mon Sep 17 00:00:00 2001 From: dcode Date: Mon, 2 Mar 2020 04:26:26 +0100 Subject: [PATCH 24/28] remaining builtin comments --- src/builtins.ts | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/builtins.ts b/src/builtins.ts index efc43abd08..cde58ffaca 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -6705,6 +6705,7 @@ function builtin_i16x8_narrow_i32x4_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_narrow_i32x4_u, builtin_i16x8_narrow_i32x4_u); +// i16x8.widen_low_i8x16_s -> v128.widen_low function builtin_i16x8_widen_low_i8x16_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6713,6 +6714,7 @@ function builtin_i16x8_widen_low_i8x16_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_widen_low_i8x16_s, builtin_i16x8_widen_low_i8x16_s); +// i16x8.widen_low_i8x16_u -> v128.widen_low function builtin_i16x8_widen_low_i8x16_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6721,6 +6723,7 @@ function builtin_i16x8_widen_low_i8x16_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_widen_low_i8x16_u, builtin_i16x8_widen_low_i8x16_u); +// i16x8.widen_high_i8x16_s -> v128.widen_high function builtin_i16x8_widen_high_i8x16_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6729,6 +6732,7 @@ function builtin_i16x8_widen_high_i8x16_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_widen_high_i8x16_s, builtin_i16x8_widen_high_i8x16_s); +// i16x8.widen_high_i8x16_u -> v128.widen_high function builtin_i16x8_widen_high_i8x16_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6737,6 +6741,7 @@ function builtin_i16x8_widen_high_i8x16_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_widen_high_i8x16_u, builtin_i16x8_widen_high_i8x16_u); +// i16x8.load8x8_s -> v128.load_ext function builtin_i16x8_load8x8_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -6745,6 +6750,7 @@ function builtin_i16x8_load8x8_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_load8x8_s, builtin_i16x8_load8x8_s); +// i16x8.load8x8_u -> v128.load_ext function builtin_i16x8_load8x8_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -6753,6 +6759,7 @@ function builtin_i16x8_load8x8_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i16x8_load8x8_u, builtin_i16x8_load8x8_u); +// i32x4.splat -> v128.splat function builtin_i32x4_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6761,6 +6768,7 @@ function builtin_i32x4_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_splat, builtin_i32x4_splat); +// i32x4.extract_lane -> v128.extract_lane function builtin_i32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6769,6 +6777,7 @@ function builtin_i32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_extract_lane, builtin_i32x4_extract_lane); +// i32x4.replace_lane -> v128.replace_lane function builtin_i32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6777,6 +6786,7 @@ function builtin_i32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_replace_lane, builtin_i32x4_replace_lane); +// i32x4.add -> v128.add function builtin_i32x4_add(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6785,6 +6795,7 @@ function builtin_i32x4_add(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_add, builtin_i32x4_add); +// i32x4.sub -> v128.sub function builtin_i32x4_sub(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6793,6 +6804,7 @@ function builtin_i32x4_sub(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_sub, builtin_i32x4_sub); +// i32x4.mul -> v128.mul function builtin_i32x4_mul(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6801,6 +6813,7 @@ function builtin_i32x4_mul(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_mul, builtin_i32x4_mul); +// i32x4.min_s -> v128.min function builtin_i32x4_min_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6809,6 +6822,7 @@ function builtin_i32x4_min_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_min_s, builtin_i32x4_min_s); +// i32x4.min_u -> v128.min function builtin_i32x4_min_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6817,6 +6831,7 @@ function builtin_i32x4_min_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_min_u, builtin_i32x4_min_u); +// i32x4.max_s -> v128.max function builtin_i32x4_max_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6825,6 +6840,7 @@ function builtin_i32x4_max_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_max_s, builtin_i32x4_max_s); +// i32x4.max_u -> v128.max function builtin_i32x4_max_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6833,6 +6849,7 @@ function builtin_i32x4_max_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_max_u, builtin_i32x4_max_u); +// i32x4.dot_i16x8_s -> v128.dot function builtin_i32x4_dot_i16x8_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6841,6 +6858,7 @@ function builtin_i32x4_dot_i16x8_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_dot_i16x8_s, builtin_i32x4_dot_i16x8_s); +// i32x4.neg -> v128.neg function builtin_i32x4_neg(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6849,6 +6867,7 @@ function builtin_i32x4_neg(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_neg, builtin_i32x4_neg); +// i32x4.shl -> v128.shl function builtin_i32x4_shl(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6857,6 +6876,7 @@ function builtin_i32x4_shl(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_shl, builtin_i32x4_shl); +// i32x4.shr_s -> v128.shr function builtin_i32x4_shr_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6865,6 +6885,7 @@ function builtin_i32x4_shr_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_shr_s, builtin_i32x4_shr_s); +// i32x4.shr_u -> v128.shr function builtin_i32x4_shr_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6873,6 +6894,7 @@ function builtin_i32x4_shr_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_shr_u, builtin_i32x4_shr_u); +// i32x4.any_true -> v128.any_true function builtin_i32x4_any_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6881,6 +6903,7 @@ function builtin_i32x4_any_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_any_true, builtin_i32x4_any_true); +// i32x4.all_true -> v128.all_true function builtin_i32x4_all_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6889,6 +6912,7 @@ function builtin_i32x4_all_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_all_true, builtin_i32x4_all_true); +// i32x4.eq -> v128.eq function builtin_i32x4_eq(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6897,6 +6921,7 @@ function builtin_i32x4_eq(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_eq, builtin_i32x4_eq); +// i32x4.ne -> v128.ne function builtin_i32x4_ne(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6905,6 +6930,7 @@ function builtin_i32x4_ne(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_ne, builtin_i32x4_ne); +// i32x4.lt_s -> v128.lt function builtin_i32x4_lt_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6913,6 +6939,7 @@ function builtin_i32x4_lt_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_lt_s, builtin_i32x4_lt_s); +// i32x4.lt_u -> v128.lt function builtin_i32x4_lt_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6921,6 +6948,7 @@ function builtin_i32x4_lt_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_lt_u, builtin_i32x4_lt_u); +// i32x4.le_s -> v128.le function builtin_i32x4_le_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6929,6 +6957,7 @@ function builtin_i32x4_le_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_le_s, builtin_i32x4_le_s); +// i32x4.le_u -> v128.le function builtin_i32x4_le_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6937,6 +6966,7 @@ function builtin_i32x4_le_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_le_u, builtin_i32x4_le_u); +// i32x4.gt_s -> v128.gt function builtin_i32x4_gt_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6945,6 +6975,7 @@ function builtin_i32x4_gt_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_gt_s, builtin_i32x4_gt_s); +// i32x4.gt_u -> v128.gt function builtin_i32x4_gt_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6953,6 +6984,7 @@ function builtin_i32x4_gt_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_gt_u, builtin_i32x4_gt_u); +// i32x4.ge_s -> v128.ge function builtin_i32x4_ge_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6961,6 +6993,7 @@ function builtin_i32x4_ge_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_ge_s, builtin_i32x4_ge_s); +// i32x4.ge_u -> v128.ge function builtin_i32x4_ge_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6969,6 +7002,7 @@ function builtin_i32x4_ge_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_ge_u, builtin_i32x4_ge_u); +// i32x4.trunc_sat_f32x4_s -> v128.trunc_sat function builtin_i32x4_trunc_sat_f32x4_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -6977,6 +7011,7 @@ function builtin_i32x4_trunc_sat_f32x4_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_trunc_sat_f32x4_s, builtin_i32x4_trunc_sat_f32x4_s); +// i32x4.trunc_sat_f32x4_u -> v128.trunc_sat function builtin_i32x4_trunc_sat_f32x4_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -6985,6 +7020,7 @@ function builtin_i32x4_trunc_sat_f32x4_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_trunc_sat_f32x4_u, builtin_i32x4_trunc_sat_f32x4_u); +// i32x4.widen_low_i16x8_s -> // v128.widen_low function builtin_i32x4_widen_low_i16x8_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -6993,6 +7029,7 @@ function builtin_i32x4_widen_low_i16x8_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_widen_low_i16x8_s, builtin_i32x4_widen_low_i16x8_s); +// i32x4.widen_low_i16x8_u -> v128.widen_low function builtin_i32x4_widen_low_i16x8_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -7001,6 +7038,7 @@ function builtin_i32x4_widen_low_i16x8_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_widen_low_i16x8_u, builtin_i32x4_widen_low_i16x8_u); +// i32x4.widen_high_i16x8_s -> v128.widen_high function builtin_i32x4_widen_high_i16x8_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -7009,6 +7047,7 @@ function builtin_i32x4_widen_high_i16x8_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_widen_high_i16x8_s, builtin_i32x4_widen_high_i16x8_s); +// i32x4.widen_high_i16x8_u -> v128.widen_high function builtin_i32x4_widen_high_i16x8_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -7017,6 +7056,7 @@ function builtin_i32x4_widen_high_i16x8_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_widen_high_i16x8_u, builtin_i32x4_widen_high_i16x8_u); +// i32x4.load16x4_s -> v128.load_ext function builtin_i32x4_load16x4_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i16 ]; @@ -7025,6 +7065,7 @@ function builtin_i32x4_load16x4_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_load16x4_s, builtin_i32x4_load16x4_s); +// i32x4.load16x4_u -> v128.load_ext function builtin_i32x4_load16x4_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -7033,6 +7074,7 @@ function builtin_i32x4_load16x4_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i32x4_load16x4_u, builtin_i32x4_load16x4_u); +// i64x2.splat -> v128.splat function builtin_i64x2_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7041,6 +7083,7 @@ function builtin_i64x2_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_splat, builtin_i64x2_splat); +// i64x2.extract_lane -> v128.extract_lane function builtin_i64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7049,6 +7092,7 @@ function builtin_i64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_extract_lane, builtin_i64x2_extract_lane); +// i64x2.replace_lane -> v128.replace_lane function builtin_i64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7057,6 +7101,7 @@ function builtin_i64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_replace_lane, builtin_i64x2_replace_lane); +// i64x2.add -> v128.add function builtin_i64x2_add(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7065,6 +7110,7 @@ function builtin_i64x2_add(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_add, builtin_i64x2_add); +// i64x2.sub -> v128.sub function builtin_i64x2_sub(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7073,6 +7119,7 @@ function builtin_i64x2_sub(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_sub, builtin_i64x2_sub); +// i64x2.neg -> v128.neg function builtin_i64x2_neg(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7081,6 +7128,7 @@ function builtin_i64x2_neg(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_neg, builtin_i64x2_neg); +// i64x2.shl -> v128.shl function builtin_i64x2_shl(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7089,6 +7137,7 @@ function builtin_i64x2_shl(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_shl, builtin_i64x2_shl); +// i64x2.shr_s -> v128.shr function builtin_i64x2_shr_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7097,6 +7146,7 @@ function builtin_i64x2_shr_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_shr_s, builtin_i64x2_shr_s); +// i64x2.shr_u -> v128.shr function builtin_i64x2_shr_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u64 ]; @@ -7105,6 +7155,7 @@ function builtin_i64x2_shr_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_shr_u, builtin_i64x2_shr_u); +// i64x2.any_true -> v128.any_true function builtin_i64x2_any_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7113,6 +7164,7 @@ function builtin_i64x2_any_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_any_true, builtin_i64x2_any_true); +// i64x2.all_true -> v128.all_true function builtin_i64x2_all_true(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7121,6 +7173,7 @@ function builtin_i64x2_all_true(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_all_true, builtin_i64x2_all_true); +// i64x2.trunc_sat_f64x2_s -> v128.trunc_sat function builtin_i64x2_trunc_sat_f64x2_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7129,6 +7182,7 @@ function builtin_i64x2_trunc_sat_f64x2_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_trunc_sat_f64x2_s, builtin_i64x2_trunc_sat_f64x2_s); +// i64x2.trunc_sat_f64x2_u -> v128.trunc_sat function builtin_i64x2_trunc_sat_f64x2_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u64 ]; @@ -7137,6 +7191,7 @@ function builtin_i64x2_trunc_sat_f64x2_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_trunc_sat_f64x2_u, builtin_i64x2_trunc_sat_f64x2_u); +// i64x2.load32x2_s -> v128.load_ext function builtin_i64x2_load32x2_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -7145,6 +7200,7 @@ function builtin_i64x2_load32x2_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_load32x2_s, builtin_i64x2_load32x2_s); +// i64x2.load32x2_u -> v128.load_ext function builtin_i64x2_load32x2_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -7153,6 +7209,7 @@ function builtin_i64x2_load32x2_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.i64x2_load32x2_u, builtin_i64x2_load32x2_u); +// f32x4.splat -> v128.splat function builtin_f32x4_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7161,6 +7218,7 @@ function builtin_f32x4_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_splat, builtin_f32x4_splat); +// f32x4.extract_lane -> v128.extract_lane function builtin_f32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7169,6 +7227,7 @@ function builtin_f32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_extract_lane, builtin_f32x4_extract_lane); +// f32x4.replace_lane -> v128.replace_lane function builtin_f32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7177,6 +7236,7 @@ function builtin_f32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_replace_lane, builtin_f32x4_replace_lane); +// f32x4.add -> v128.add function builtin_f32x4_add(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7185,6 +7245,7 @@ function builtin_f32x4_add(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_add, builtin_f32x4_add); +// f32x4.sub -> v128.sub function builtin_f32x4_sub(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7193,6 +7254,7 @@ function builtin_f32x4_sub(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_sub, builtin_f32x4_sub); +// f32x4.mul -> v128.mul function builtin_f32x4_mul(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7201,6 +7263,7 @@ function builtin_f32x4_mul(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_mul, builtin_f32x4_mul); +// f32x4.div -> v128.div function builtin_f32x4_div(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7209,6 +7272,7 @@ function builtin_f32x4_div(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_div, builtin_f32x4_div); +// f32x4.neg -> v128.neg function builtin_f32x4_neg(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7217,6 +7281,7 @@ function builtin_f32x4_neg(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_neg, builtin_f32x4_neg); +// f32x4.min -> v128.min function builtin_f32x4_min(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7225,6 +7290,7 @@ function builtin_f32x4_min(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_min, builtin_f32x4_min); +// f32x4.max -> v128.max function builtin_f32x4_max(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7233,6 +7299,7 @@ function builtin_f32x4_max(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_max, builtin_f32x4_max); +// f32x4.abs -> v128.abs function builtin_f32x4_abs(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7241,6 +7308,7 @@ function builtin_f32x4_abs(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_abs, builtin_f32x4_abs); +// f32x4.sqrt -> v128.sqrt function builtin_f32x4_sqrt(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7249,6 +7317,7 @@ function builtin_f32x4_sqrt(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_sqrt, builtin_f32x4_sqrt); +// f32x4.eq -> v128.eq function builtin_f32x4_eq(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7257,6 +7326,7 @@ function builtin_f32x4_eq(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_eq, builtin_f32x4_eq); +// f32x4.ne -> v128.ne function builtin_f32x4_ne(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7265,6 +7335,7 @@ function builtin_f32x4_ne(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_ne, builtin_f32x4_ne); +// f32x4.lt -> v128.lt function builtin_f32x4_lt(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7273,6 +7344,7 @@ function builtin_f32x4_lt(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_lt, builtin_f32x4_lt); +// f32x4.le -> v128.le function builtin_f32x4_le(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7281,6 +7353,7 @@ function builtin_f32x4_le(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_le, builtin_f32x4_le); +// f32x4.gt -> v128.gt function builtin_f32x4_gt(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7289,6 +7362,7 @@ function builtin_f32x4_gt(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_gt, builtin_f32x4_gt); +// f32x4.ge -> v128.ge function builtin_f32x4_ge(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7297,6 +7371,7 @@ function builtin_f32x4_ge(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_ge, builtin_f32x4_ge); +// f32x4.convert_i32x4_s -> v128.convert function builtin_f32x4_convert_i32x4_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i32 ]; @@ -7305,6 +7380,7 @@ function builtin_f32x4_convert_i32x4_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_convert_i32x4_s, builtin_f32x4_convert_i32x4_s); +// f32x4.convert_i32x4_u -> v128.convert function builtin_f32x4_convert_i32x4_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -7313,6 +7389,7 @@ function builtin_f32x4_convert_i32x4_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_convert_i32x4_u, builtin_f32x4_convert_i32x4_u); +// f32x4.qfma -> v128.qfma function builtin_f32x4_qfma(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7321,6 +7398,7 @@ function builtin_f32x4_qfma(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_qfma, builtin_f32x4_qfma); +// f32x4.qfms -> v128.qfms function builtin_f32x4_qfms(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f32 ]; @@ -7329,6 +7407,7 @@ function builtin_f32x4_qfms(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f32x4_qfms, builtin_f32x4_qfms); +// f64x2.splat -> v128.splat function builtin_f64x2_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7337,6 +7416,7 @@ function builtin_f64x2_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_splat, builtin_f64x2_splat); +// f64x2.extract_lane -> v128.extract_lane function builtin_f64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7345,6 +7425,7 @@ function builtin_f64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_extract_lane, builtin_f64x2_extract_lane); +// f64x2.replace_lane -> v128.replace_lane function builtin_f64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7353,6 +7434,7 @@ function builtin_f64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_replace_lane, builtin_f64x2_replace_lane); +// f64x2.add -> v128.add function builtin_f64x2_add(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7361,6 +7443,7 @@ function builtin_f64x2_add(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_add, builtin_f64x2_add); +// f64x2.sub -> v128.sub function builtin_f64x2_sub(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7369,6 +7452,7 @@ function builtin_f64x2_sub(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_sub, builtin_f64x2_sub); +// f64x2.mul -> v128.mul function builtin_f64x2_mul(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7377,6 +7461,7 @@ function builtin_f64x2_mul(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_mul, builtin_f64x2_mul); +// f64x2.div -> v128.div function builtin_f64x2_div(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7385,6 +7470,7 @@ function builtin_f64x2_div(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_div, builtin_f64x2_div); +// f64x2.neg -> v128.neg function builtin_f64x2_neg(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7393,6 +7479,7 @@ function builtin_f64x2_neg(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_neg, builtin_f64x2_neg); +// f64x2.min -> v128.min function builtin_f64x2_min(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7401,6 +7488,7 @@ function builtin_f64x2_min(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_min, builtin_f64x2_min); +// f64x2.max -> v128.max function builtin_f64x2_max(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7409,6 +7497,7 @@ function builtin_f64x2_max(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_max, builtin_f64x2_max); +// f64x2.abs -> v128.abs function builtin_f64x2_abs(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7417,6 +7506,7 @@ function builtin_f64x2_abs(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_abs, builtin_f64x2_abs); +// f64x2.sqrt -> v128.sqrt function builtin_f64x2_sqrt(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7425,6 +7515,7 @@ function builtin_f64x2_sqrt(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_sqrt, builtin_f64x2_sqrt); +// f64x2.eq -> v128.eq function builtin_f64x2_eq(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7433,6 +7524,7 @@ function builtin_f64x2_eq(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_eq, builtin_f64x2_eq); +// f64x2.ne -> v128.ne function builtin_f64x2_ne(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7441,6 +7533,7 @@ function builtin_f64x2_ne(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_ne, builtin_f64x2_ne); +// f64x2.lt -> v128.lt function builtin_f64x2_lt(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7449,6 +7542,7 @@ function builtin_f64x2_lt(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_lt, builtin_f64x2_lt); +// f64x2.le -> v128.le function builtin_f64x2_le(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7457,6 +7551,7 @@ function builtin_f64x2_le(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_le, builtin_f64x2_le); +// f64x2.gt -> v128.gt function builtin_f64x2_gt(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7465,6 +7560,7 @@ function builtin_f64x2_gt(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_gt, builtin_f64x2_gt); +// f64x2.ge -> v128.ge function builtin_f64x2_ge(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7473,6 +7569,7 @@ function builtin_f64x2_ge(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_ge, builtin_f64x2_ge); +// f64x2.convert_i64x2_s -> v128.convert function builtin_f64x2_convert_i64x2_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i64 ]; @@ -7481,6 +7578,7 @@ function builtin_f64x2_convert_i64x2_s(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_convert_i64x2_s, builtin_f64x2_convert_i64x2_s); +// f64x2.convert_i64x2_u -> v128.convert function builtin_f64x2_convert_i64x2_u(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u64 ]; @@ -7489,6 +7587,7 @@ function builtin_f64x2_convert_i64x2_u(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_convert_i64x2_u, builtin_f64x2_convert_i64x2_u); +// f64x2.qfma -> v128.qfma function builtin_f64x2_qfma(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7497,6 +7596,7 @@ function builtin_f64x2_qfma(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_qfma, builtin_f64x2_qfma); +// f64x2.qfms -> v128.qfms function builtin_f64x2_qfms(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.f64 ]; @@ -7505,6 +7605,7 @@ function builtin_f64x2_qfms(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64x2_qfms, builtin_f64x2_qfms); +// v8x16.shuffle -> v128.shuffle function builtin_v8x16_shuffle(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.i8 ]; @@ -7513,6 +7614,7 @@ function builtin_v8x16_shuffle(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.v8x16_shuffle, builtin_v8x16_shuffle); +// v8x16.swizzle -> v128.swizzle function builtin_v8x16_swizzle(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = null; @@ -7521,6 +7623,7 @@ function builtin_v8x16_swizzle(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.v8x16_swizzle, builtin_v8x16_swizzle); +// v8x16.load_splat -> v128.load_splat function builtin_v8x16_load_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u8 ]; @@ -7529,6 +7632,7 @@ function builtin_v8x16_load_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.v8x16_load_splat, builtin_v8x16_load_splat); +// v16x8.load_splat -> v128.load_splat function builtin_v16x8_load_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u16 ]; @@ -7537,6 +7641,7 @@ function builtin_v16x8_load_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.v16x8_load_splat, builtin_v16x8_load_splat); +// v32x4.load_splat -> v128.load_splat function builtin_v32x4_load_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u32 ]; @@ -7545,6 +7650,7 @@ function builtin_v32x4_load_splat(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.v32x4_load_splat, builtin_v32x4_load_splat); +// v64x2.load_splat -> v128.load_splat function builtin_v64x2_load_splat(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); ctx.typeArguments = [ Type.u64 ]; From 94581f07a090e62fb6902e236f55421ce809cecd Mon Sep 17 00:00:00 2001 From: dcode Date: Mon, 2 Mar 2020 05:52:25 +0100 Subject: [PATCH 25/28] fix #1138 --- src/compiler.ts | 25 +++- src/program.ts | 3 +- std/assembly/util/number.ts | 4 +- tests/compiler/do.optimized.wat | 43 ++++-- tests/compiler/do.ts | 9 ++ tests/compiler/do.untouched.wat | 123 ++++++++++------ tests/compiler/number.untouched.wat | 2 +- tests/compiler/resolve-binary.untouched.wat | 2 +- .../resolve-elementaccess.untouched.wat | 2 +- tests/compiler/resolve-ternary.untouched.wat | 2 +- tests/compiler/std/array.untouched.wat | 2 +- tests/compiler/std/string.untouched.wat | 2 +- tests/compiler/std/typedarray.untouched.wat | 2 +- tests/compiler/while.optimized.wat | 43 ++++-- tests/compiler/while.ts | 9 ++ tests/compiler/while.untouched.wat | 131 +++++++++++------- 16 files changed, 276 insertions(+), 128 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 579622c9a5..f68012a6e6 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -2175,6 +2175,20 @@ export class Compiler extends DiagnosticEmitter { } this.performAutoreleases(condFlow, bodyStmts); flow.inherit(bodyFlow); + + // Terminate if condition is always true and body never breaks + } else if (condKind == ConditionKind.TRUE && !bodyFlow.isAny(FlowFlags.BREAKS | FlowFlags.CONDITIONALLY_BREAKS)) { + if (hasSideEffects(condExpr)) { + bodyStmts.push( + module.drop(condExpr) + ); + } + this.performAutoreleases(condFlow, bodyStmts); + bodyStmts.push( + module.br(continueLabel) + ); + flow.set(FlowFlags.TERMINATES); + } else { let tcond = condFlow.getTempLocal(Type.bool); bodyStmts.push( @@ -3082,13 +3096,22 @@ export class Compiler extends DiagnosticEmitter { bodyStmts.push(this.compileStatement(body)); } - // Check if body terminates + // Simplify if body always terminates if (bodyFlow.is(FlowFlags.TERMINATES)) { bodyStmts.push( module.unreachable() ); if (condKind == ConditionKind.TRUE) flow.inherit(bodyFlow); else flow.inheritBranch(bodyFlow); + + // Terminate if condition is always true and body never breaks + } else if (condKind == ConditionKind.TRUE && !bodyFlow.isAny(FlowFlags.BREAKS | FlowFlags.CONDITIONALLY_BREAKS)) { + this.performAutoreleases(bodyFlow, bodyStmts); + bodyStmts.push( + module.br(continueLabel) + ); + flow.set(FlowFlags.TERMINATES); + } else { let breaks = bodyFlow.is(FlowFlags.BREAKS); if (breaks) { diff --git a/src/program.ts b/src/program.ts index cf3b38ecb3..5d7f7a018a 100644 --- a/src/program.ts +++ b/src/program.ts @@ -2193,7 +2193,6 @@ export abstract class Element { current = current.parent; if (current.kind == ElementKind.FILE) return current; } while (true); - return unreachable(); } /** Tests if this element has a specific flag or flags. */ @@ -2215,7 +2214,7 @@ export abstract class Element { } /** Looks up the element with the specified name relative to this element, like in JS. */ - /* abstract */ lookup(name: string): Element | null { return unreachable(); } + /* abstract */ lookup(name: string): Element | null { return unreachable(); } /** Adds an element as a member of this one. Reports and returns `false` if a duplicate. */ add(name: string, element: DeclaredElement, localIdentifierIfImport: IdentifierExpression | null = null): bool { diff --git a/std/assembly/util/number.ts b/std/assembly/util/number.ts index ecbe1efcbc..6e57aaa5ca 100644 --- a/std/assembly/util/number.ts +++ b/std/assembly/util/number.ts @@ -499,7 +499,7 @@ function genDigits(buffer: usize, w_frc: u64, w_exp: i32, mp_frc: u64, mp_exp: i } } - while (1) { + while (true) { p2 *= 10; delta *= 10; @@ -515,8 +515,6 @@ function genDigits(buffer: usize, w_frc: u64, w_exp: i32, mp_frc: u64, mp_exp: i return len; } } - - return len; } // @ts-ignore: decorator diff --git a/tests/compiler/do.optimized.wat b/tests/compiler/do.optimized.wat index 679f0a64c1..0a93f4ce92 100644 --- a/tests/compiler/do.optimized.wat +++ b/tests/compiler/do.optimized.wat @@ -214,7 +214,7 @@ if i32.const 0 i32.const 32 - i32.const 107 + i32.const 116 i32.const 2 call $~lib/builtins/abort unreachable @@ -251,7 +251,7 @@ if i32.const 0 i32.const 32 - i32.const 125 + i32.const 134 i32.const 2 call $~lib/builtins/abort unreachable @@ -262,7 +262,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -1265,7 +1265,7 @@ if i32.const 0 i32.const 32 - i32.const 141 + i32.const 150 i32.const 2 call $~lib/builtins/abort unreachable @@ -1274,7 +1274,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1323,7 +1323,7 @@ if i32.const 0 i32.const 32 - i32.const 161 + i32.const 170 i32.const 2 call $~lib/builtins/abort unreachable @@ -1332,7 +1332,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -1343,6 +1343,7 @@ call $~lib/rt/pure/__release ) (func $start:do (; 24 ;) + (local $0 i32) i32.const 0 global.set $do/ran call $do/testSimple @@ -1395,6 +1396,26 @@ call $~lib/builtins/abort unreachable end + loop $do-continue|0 + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.ne + br_if $do-continue|0 + end + local.get $0 + i32.const 10 + i32.ne + if + i32.const 0 + i32.const 32 + i32.const 70 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $do/ran i32.const 1 @@ -1415,7 +1436,7 @@ if i32.const 0 i32.const 32 - i32.const 112 + i32.const 121 i32.const 0 call $~lib/builtins/abort unreachable @@ -1428,7 +1449,7 @@ if i32.const 0 i32.const 32 - i32.const 131 + i32.const 140 i32.const 0 call $~lib/builtins/abort unreachable @@ -1441,7 +1462,7 @@ if i32.const 0 i32.const 32 - i32.const 147 + i32.const 156 i32.const 0 call $~lib/builtins/abort unreachable @@ -1454,7 +1475,7 @@ if i32.const 0 i32.const 32 - i32.const 167 + i32.const 176 i32.const 0 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/do.ts b/tests/compiler/do.ts index 82cdbc8f4e..c7de4222eb 100644 --- a/tests/compiler/do.ts +++ b/tests/compiler/do.ts @@ -60,6 +60,15 @@ ran = false; testAlwaysTrue(); assert(ran); +function testAlwaysTrueNeverBreaks(): i32 { + var i = 0; + do { + if (++i == 10) return i; + } while (true); + // no return required +} +assert(testAlwaysTrueNeverBreaks() == 10); + function testAlwaysFalse(): void { var i = 0; do { diff --git a/tests/compiler/do.untouched.wat b/tests/compiler/do.untouched.wat index 8f7f07a553..2a12469761 100644 --- a/tests/compiler/do.untouched.wat +++ b/tests/compiler/do.untouched.wat @@ -2,8 +2,8 @@ (type $none_=>_none (func)) (type $i32_=>_none (func (param i32))) (type $i32_i32_=>_none (func (param i32 i32))) - (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) + (type $i32_=>_i32 (func (param i32) (result i32))) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32))) (type $i32_i32_i32_=>_none (func (param i32 i32 i32))) @@ -247,7 +247,26 @@ i32.const 1 global.set $do/ran ) - (func $do/testAlwaysFalse (; 9 ;) + (func $do/testAlwaysTrueNeverBreaks (; 9 ;) (result i32) + (local $0 i32) + i32.const 0 + local.set $0 + loop $do-continue|0 + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.eq + if + local.get $0 + return + end + br $do-continue|0 + end + unreachable + ) + (func $do/testAlwaysFalse (; 10 ;) (local $0 i32) i32.const 0 local.set $0 @@ -264,7 +283,7 @@ if i32.const 0 i32.const 32 - i32.const 68 + i32.const 77 i32.const 2 call $~lib/builtins/abort unreachable @@ -272,7 +291,7 @@ i32.const 1 global.set $do/ran ) - (func $do/testAlwaysBreaks (; 10 ;) + (func $do/testAlwaysBreaks (; 11 ;) (local $0 i32) i32.const 0 local.set $0 @@ -293,7 +312,7 @@ if i32.const 0 i32.const 32 - i32.const 81 + i32.const 90 i32.const 2 call $~lib/builtins/abort unreachable @@ -301,7 +320,7 @@ i32.const 1 global.set $do/ran ) - (func $do/testAlwaysReturns (; 11 ;) + (func $do/testAlwaysReturns (; 12 ;) (local $0 i32) i32.const 0 local.set $0 @@ -316,7 +335,7 @@ end unreachable ) - (func $do/testContinue (; 12 ;) + (func $do/testContinue (; 13 ;) (local $0 i32) i32.const 0 local.set $0 @@ -342,7 +361,7 @@ if i32.const 0 i32.const 32 - i32.const 107 + i32.const 116 i32.const 2 call $~lib/builtins/abort unreachable @@ -350,7 +369,7 @@ i32.const 1 global.set $do/ran ) - (func $do/testNestedContinue (; 13 ;) + (func $do/testNestedContinue (; 14 ;) (local $0 i32) (local $1 i32) i32.const 0 @@ -396,7 +415,7 @@ if i32.const 0 i32.const 32 - i32.const 125 + i32.const 134 i32.const 2 call $~lib/builtins/abort unreachable @@ -408,7 +427,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -416,7 +435,7 @@ i32.const 1 global.set $do/ran ) - (func $~lib/rt/tlsf/removeBlock (; 14 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/removeBlock (; 15 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -626,7 +645,7 @@ end end ) - (func $~lib/rt/tlsf/insertBlock (; 15 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/insertBlock (; 16 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -976,7 +995,7 @@ local.get $7 i32.store offset=4 ) - (func $~lib/rt/tlsf/addMemory (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/addMemory (; 17 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1124,7 +1143,7 @@ call $~lib/rt/tlsf/insertBlock i32.const 1 ) - (func $~lib/rt/tlsf/maybeInitialize (; 17 ;) (result i32) + (func $~lib/rt/tlsf/maybeInitialize (; 18 ;) (result i32) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1274,7 +1293,7 @@ end local.get $0 ) - (func $~lib/rt/tlsf/prepareSize (; 18 ;) (param $0 i32) (result i32) + (func $~lib/rt/tlsf/prepareSize (; 19 ;) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) local.get $0 @@ -1303,7 +1322,7 @@ i32.gt_u select ) - (func $~lib/rt/tlsf/searchBlock (; 19 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/searchBlock (; 20 ;) (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1486,7 +1505,7 @@ end local.get $7 ) - (func $~lib/rt/tlsf/growMemory (; 20 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/growMemory (; 21 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1570,7 +1589,7 @@ call $~lib/rt/tlsf/addMemory drop ) - (func $~lib/rt/tlsf/prepareBlock (; 21 ;) (param $0 i32) (param $1 i32) (param $2 i32) + (func $~lib/rt/tlsf/prepareBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1665,7 +1684,7 @@ i32.store end ) - (func $~lib/rt/tlsf/allocateBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/allocateBlock (; 23 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) global.get $~lib/rt/tlsf/collectLock @@ -1776,7 +1795,7 @@ call $~lib/rt/rtrace/onalloc local.get $4 ) - (func $~lib/rt/tlsf/__alloc (; 23 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/__alloc (; 24 ;) (param $0 i32) (param $1 i32) (result i32) call $~lib/rt/tlsf/maybeInitialize local.get $0 local.get $1 @@ -1784,7 +1803,7 @@ i32.const 16 i32.add ) - (func $~lib/rt/pure/increment (; 24 ;) (param $0 i32) + (func $~lib/rt/pure/increment (; 25 ;) (param $0 i32) (local $1 i32) local.get $0 i32.load offset=4 @@ -1829,7 +1848,7 @@ unreachable end ) - (func $~lib/rt/pure/__retain (; 25 ;) (param $0 i32) (result i32) + (func $~lib/rt/pure/__retain (; 26 ;) (param $0 i32) (result i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1841,7 +1860,7 @@ end local.get $0 ) - (func $do/Ref#constructor (; 26 ;) (param $0 i32) (result i32) + (func $do/Ref#constructor (; 27 ;) (param $0 i32) (result i32) local.get $0 i32.eqz if @@ -1853,7 +1872,7 @@ end local.get $0 ) - (func $~lib/rt/pure/__release (; 27 ;) (param $0 i32) + (func $~lib/rt/pure/__release (; 28 ;) (param $0 i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1864,7 +1883,7 @@ call $~lib/rt/pure/decrement end ) - (func $do/testRef (; 28 ;) + (func $do/testRef (; 29 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1917,7 +1936,7 @@ if i32.const 0 i32.const 32 - i32.const 141 + i32.const 150 i32.const 2 call $~lib/builtins/abort unreachable @@ -1928,7 +1947,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1938,11 +1957,11 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $do/getRef (; 29 ;) (result i32) + (func $do/getRef (; 30 ;) (result i32) i32.const 0 call $do/Ref#constructor ) - (func $do/testRefAutorelease (; 30 ;) + (func $do/testRefAutorelease (; 31 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1993,7 +2012,7 @@ if i32.const 0 i32.const 32 - i32.const 161 + i32.const 170 i32.const 2 call $~lib/builtins/abort unreachable @@ -2004,7 +2023,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -2014,7 +2033,7 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $start:do (; 31 ;) + (func $start:do (; 32 ;) i32.const 0 global.set $do/ran call $do/testSimple @@ -2067,6 +2086,18 @@ call $~lib/builtins/abort unreachable end + call $do/testAlwaysTrueNeverBreaks + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 70 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $do/ran call $do/testAlwaysFalse @@ -2075,7 +2106,7 @@ if i32.const 0 i32.const 32 - i32.const 73 + i32.const 82 i32.const 0 call $~lib/builtins/abort unreachable @@ -2088,7 +2119,7 @@ if i32.const 0 i32.const 32 - i32.const 86 + i32.const 95 i32.const 0 call $~lib/builtins/abort unreachable @@ -2101,7 +2132,7 @@ if i32.const 0 i32.const 32 - i32.const 99 + i32.const 108 i32.const 0 call $~lib/builtins/abort unreachable @@ -2114,7 +2145,7 @@ if i32.const 0 i32.const 32 - i32.const 112 + i32.const 121 i32.const 0 call $~lib/builtins/abort unreachable @@ -2127,7 +2158,7 @@ if i32.const 0 i32.const 32 - i32.const 131 + i32.const 140 i32.const 0 call $~lib/builtins/abort unreachable @@ -2140,7 +2171,7 @@ if i32.const 0 i32.const 32 - i32.const 147 + i32.const 156 i32.const 0 call $~lib/builtins/abort unreachable @@ -2153,13 +2184,13 @@ if i32.const 0 i32.const 32 - i32.const 167 + i32.const 176 i32.const 0 call $~lib/builtins/abort unreachable end ) - (func $~start (; 32 ;) + (func $~start (; 33 ;) global.get $~started if return @@ -2169,10 +2200,10 @@ end call $start:do ) - (func $~lib/rt/pure/__collect (; 33 ;) + (func $~lib/rt/pure/__collect (; 34 ;) return ) - (func $~lib/rt/tlsf/freeBlock (; 34 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/freeBlock (; 35 ;) (param $0 i32) (param $1 i32) (local $2 i32) local.get $1 i32.load @@ -2188,7 +2219,7 @@ local.get $1 call $~lib/rt/rtrace/onfree ) - (func $~lib/rt/pure/decrement (; 35 ;) (param $0 i32) + (func $~lib/rt/pure/decrement (; 36 ;) (param $0 i32) (local $1 i32) (local $2 i32) local.get $0 @@ -2265,7 +2296,7 @@ i32.store offset=4 end ) - (func $~lib/rt/pure/__visit (; 36 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/pure/__visit (; 37 ;) (param $0 i32) (param $1 i32) local.get $0 global.get $~lib/heap/__heap_base i32.lt_u @@ -2289,7 +2320,7 @@ i32.sub call $~lib/rt/pure/decrement ) - (func $~lib/rt/__visit_members (; 37 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/__visit_members (; 38 ;) (param $0 i32) (param $1 i32) (local $2 i32) block $switch$1$default block $switch$1$case$4 diff --git a/tests/compiler/number.untouched.wat b/tests/compiler/number.untouched.wat index 09c098a4ff..ac383e96e8 100644 --- a/tests/compiler/number.untouched.wat +++ b/tests/compiler/number.untouched.wat @@ -1142,7 +1142,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 14 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/resolve-binary.untouched.wat b/tests/compiler/resolve-binary.untouched.wat index dd2e953b7f..3e2365707a 100644 --- a/tests/compiler/resolve-binary.untouched.wat +++ b/tests/compiler/resolve-binary.untouched.wat @@ -2122,7 +2122,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/resolve-elementaccess.untouched.wat b/tests/compiler/resolve-elementaccess.untouched.wat index 3fc1cec58b..037c081a55 100644 --- a/tests/compiler/resolve-elementaccess.untouched.wat +++ b/tests/compiler/resolve-elementaccess.untouched.wat @@ -1126,7 +1126,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 12 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/resolve-ternary.untouched.wat b/tests/compiler/resolve-ternary.untouched.wat index 9fe36fff07..986b55803c 100644 --- a/tests/compiler/resolve-ternary.untouched.wat +++ b/tests/compiler/resolve-ternary.untouched.wat @@ -2463,7 +2463,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 23 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/std/array.untouched.wat b/tests/compiler/std/array.untouched.wat index b5125b29bf..3ed0943687 100644 --- a/tests/compiler/std/array.untouched.wat +++ b/tests/compiler/std/array.untouched.wat @@ -13442,7 +13442,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/number/prettify (; 251 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) diff --git a/tests/compiler/std/string.untouched.wat b/tests/compiler/std/string.untouched.wat index 77840a1aaf..ea9a9bf04a 100644 --- a/tests/compiler/std/string.untouched.wat +++ b/tests/compiler/std/string.untouched.wat @@ -9817,7 +9817,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/number/prettify (; 88 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) diff --git a/tests/compiler/std/typedarray.untouched.wat b/tests/compiler/std/typedarray.untouched.wat index cc73f6ad8a..2f995e4d76 100644 --- a/tests/compiler/std/typedarray.untouched.wat +++ b/tests/compiler/std/typedarray.untouched.wat @@ -35621,7 +35621,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/number/prettify (; 537 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) diff --git a/tests/compiler/while.optimized.wat b/tests/compiler/while.optimized.wat index 8c300ec39a..af8e967f10 100644 --- a/tests/compiler/while.optimized.wat +++ b/tests/compiler/while.optimized.wat @@ -243,7 +243,7 @@ if i32.const 0 i32.const 32 - i32.const 108 + i32.const 117 i32.const 2 call $~lib/builtins/abort unreachable @@ -282,7 +282,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -291,7 +291,7 @@ if i32.const 0 i32.const 32 - i32.const 127 + i32.const 136 i32.const 2 call $~lib/builtins/abort unreachable @@ -1297,7 +1297,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1306,7 +1306,7 @@ if i32.const 0 i32.const 32 - i32.const 143 + i32.const 152 i32.const 2 call $~lib/builtins/abort unreachable @@ -1357,7 +1357,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -1366,7 +1366,7 @@ if i32.const 0 i32.const 32 - i32.const 163 + i32.const 172 i32.const 2 call $~lib/builtins/abort unreachable @@ -1377,6 +1377,7 @@ call $~lib/rt/pure/__release ) (func $start:while (; 24 ;) + (local $0 i32) i32.const 0 global.set $while/ran call $while/testSimple @@ -1429,6 +1430,26 @@ call $~lib/builtins/abort unreachable end + loop $while-continue|0 + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.ne + br_if $while-continue|0 + end + local.get $0 + i32.const 10 + i32.ne + if + i32.const 0 + i32.const 32 + i32.const 72 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $while/ran i32.const 1 @@ -1449,7 +1470,7 @@ if i32.const 0 i32.const 32 - i32.const 113 + i32.const 122 i32.const 0 call $~lib/builtins/abort unreachable @@ -1462,7 +1483,7 @@ if i32.const 0 i32.const 32 - i32.const 132 + i32.const 141 i32.const 0 call $~lib/builtins/abort unreachable @@ -1475,7 +1496,7 @@ if i32.const 0 i32.const 32 - i32.const 148 + i32.const 157 i32.const 0 call $~lib/builtins/abort unreachable @@ -1488,7 +1509,7 @@ if i32.const 0 i32.const 32 - i32.const 168 + i32.const 177 i32.const 0 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/while.ts b/tests/compiler/while.ts index 1a8e98548c..43e5e768f7 100644 --- a/tests/compiler/while.ts +++ b/tests/compiler/while.ts @@ -62,6 +62,15 @@ ran = false; testAlwaysTrue(); assert(ran); +function testAlwaysTrueNeverBreaks(): i32 { + var i = 0; + while (true) { + if (++i == 10) return i; + } + // no return required +} +assert(testAlwaysTrueNeverBreaks() == 10); + function testAlwaysFalse(): void { var i = 0; while (false) { diff --git a/tests/compiler/while.untouched.wat b/tests/compiler/while.untouched.wat index 08894a2c67..da51f635c6 100644 --- a/tests/compiler/while.untouched.wat +++ b/tests/compiler/while.untouched.wat @@ -2,8 +2,8 @@ (type $none_=>_none (func)) (type $i32_=>_none (func (param i32))) (type $i32_i32_=>_none (func (param i32 i32))) - (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) + (type $i32_=>_i32 (func (param i32) (result i32))) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32))) (type $i32_i32_i32_=>_none (func (param i32 i32 i32))) @@ -281,7 +281,32 @@ i32.const 1 global.set $while/ran ) - (func $while/testAlwaysFalse (; 9 ;) + (func $while/testAlwaysTrueNeverBreaks (; 9 ;) (result i32) + (local $0 i32) + (local $1 i32) + i32.const 0 + local.set $0 + loop $while-continue|0 + i32.const 1 + local.set $1 + local.get $1 + if + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.eq + if + local.get $0 + return + end + br $while-continue|0 + end + end + unreachable + ) + (func $while/testAlwaysFalse (; 10 ;) (local $0 i32) i32.const 0 local.set $0 @@ -292,7 +317,7 @@ if i32.const 0 i32.const 32 - i32.const 71 + i32.const 80 i32.const 2 call $~lib/builtins/abort unreachable @@ -300,7 +325,7 @@ i32.const 1 global.set $while/ran ) - (func $while/testAlwaysBreaks (; 10 ;) + (func $while/testAlwaysBreaks (; 11 ;) (local $0 i32) (local $1 i32) i32.const 0 @@ -325,7 +350,7 @@ if i32.const 0 i32.const 32 - i32.const 83 + i32.const 92 i32.const 2 call $~lib/builtins/abort unreachable @@ -333,7 +358,7 @@ i32.const 1 global.set $while/ran ) - (func $while/testAlwaysReturns (; 11 ;) + (func $while/testAlwaysReturns (; 12 ;) (local $0 i32) (local $1 i32) i32.const 0 @@ -356,13 +381,13 @@ if i32.const 0 i32.const 32 - i32.const 96 + i32.const 105 i32.const 2 call $~lib/builtins/abort unreachable end ) - (func $while/testContinue (; 12 ;) + (func $while/testContinue (; 13 ;) (local $0 i32) (local $1 i32) i32.const 10 @@ -386,7 +411,7 @@ if i32.const 0 i32.const 32 - i32.const 108 + i32.const 117 i32.const 2 call $~lib/builtins/abort unreachable @@ -394,7 +419,7 @@ i32.const 1 global.set $while/ran ) - (func $while/testNestedContinue (; 13 ;) + (func $while/testNestedContinue (; 14 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -434,7 +459,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -446,7 +471,7 @@ if i32.const 0 i32.const 32 - i32.const 127 + i32.const 136 i32.const 2 call $~lib/builtins/abort unreachable @@ -454,7 +479,7 @@ i32.const 1 global.set $while/ran ) - (func $~lib/rt/tlsf/removeBlock (; 14 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/removeBlock (; 15 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -664,7 +689,7 @@ end end ) - (func $~lib/rt/tlsf/insertBlock (; 15 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/insertBlock (; 16 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1014,7 +1039,7 @@ local.get $7 i32.store offset=4 ) - (func $~lib/rt/tlsf/addMemory (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/addMemory (; 17 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1162,7 +1187,7 @@ call $~lib/rt/tlsf/insertBlock i32.const 1 ) - (func $~lib/rt/tlsf/maybeInitialize (; 17 ;) (result i32) + (func $~lib/rt/tlsf/maybeInitialize (; 18 ;) (result i32) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1312,7 +1337,7 @@ end local.get $0 ) - (func $~lib/rt/tlsf/prepareSize (; 18 ;) (param $0 i32) (result i32) + (func $~lib/rt/tlsf/prepareSize (; 19 ;) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) local.get $0 @@ -1341,7 +1366,7 @@ i32.gt_u select ) - (func $~lib/rt/tlsf/searchBlock (; 19 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/searchBlock (; 20 ;) (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1524,7 +1549,7 @@ end local.get $7 ) - (func $~lib/rt/tlsf/growMemory (; 20 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/growMemory (; 21 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1608,7 +1633,7 @@ call $~lib/rt/tlsf/addMemory drop ) - (func $~lib/rt/tlsf/prepareBlock (; 21 ;) (param $0 i32) (param $1 i32) (param $2 i32) + (func $~lib/rt/tlsf/prepareBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1703,7 +1728,7 @@ i32.store end ) - (func $~lib/rt/tlsf/allocateBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/allocateBlock (; 23 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) global.get $~lib/rt/tlsf/collectLock @@ -1814,7 +1839,7 @@ call $~lib/rt/rtrace/onalloc local.get $4 ) - (func $~lib/rt/tlsf/__alloc (; 23 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/__alloc (; 24 ;) (param $0 i32) (param $1 i32) (result i32) call $~lib/rt/tlsf/maybeInitialize local.get $0 local.get $1 @@ -1822,7 +1847,7 @@ i32.const 16 i32.add ) - (func $~lib/rt/pure/increment (; 24 ;) (param $0 i32) + (func $~lib/rt/pure/increment (; 25 ;) (param $0 i32) (local $1 i32) local.get $0 i32.load offset=4 @@ -1867,7 +1892,7 @@ unreachable end ) - (func $~lib/rt/pure/__retain (; 25 ;) (param $0 i32) (result i32) + (func $~lib/rt/pure/__retain (; 26 ;) (param $0 i32) (result i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1879,7 +1904,7 @@ end local.get $0 ) - (func $while/Ref#constructor (; 26 ;) (param $0 i32) (result i32) + (func $while/Ref#constructor (; 27 ;) (param $0 i32) (result i32) local.get $0 i32.eqz if @@ -1891,7 +1916,7 @@ end local.get $0 ) - (func $~lib/rt/pure/__release (; 27 ;) (param $0 i32) + (func $~lib/rt/pure/__release (; 28 ;) (param $0 i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1902,7 +1927,7 @@ call $~lib/rt/pure/decrement end ) - (func $while/testRef (; 28 ;) + (func $while/testRef (; 29 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1958,7 +1983,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1969,7 +1994,7 @@ if i32.const 0 i32.const 32 - i32.const 143 + i32.const 152 i32.const 2 call $~lib/builtins/abort unreachable @@ -1979,11 +2004,11 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $while/getRef (; 29 ;) (result i32) + (func $while/getRef (; 30 ;) (result i32) i32.const 0 call $while/Ref#constructor ) - (func $while/testRefAutorelease (; 30 ;) + (func $while/testRefAutorelease (; 31 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -2037,7 +2062,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -2048,7 +2073,7 @@ if i32.const 0 i32.const 32 - i32.const 163 + i32.const 172 i32.const 2 call $~lib/builtins/abort unreachable @@ -2058,7 +2083,7 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $start:while (; 31 ;) + (func $start:while (; 32 ;) i32.const 0 global.set $while/ran call $while/testSimple @@ -2111,6 +2136,18 @@ call $~lib/builtins/abort unreachable end + call $while/testAlwaysTrueNeverBreaks + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 72 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $while/ran call $while/testAlwaysFalse @@ -2119,7 +2156,7 @@ if i32.const 0 i32.const 32 - i32.const 76 + i32.const 85 i32.const 0 call $~lib/builtins/abort unreachable @@ -2132,7 +2169,7 @@ if i32.const 0 i32.const 32 - i32.const 88 + i32.const 97 i32.const 0 call $~lib/builtins/abort unreachable @@ -2145,7 +2182,7 @@ if i32.const 0 i32.const 32 - i32.const 100 + i32.const 109 i32.const 0 call $~lib/builtins/abort unreachable @@ -2158,7 +2195,7 @@ if i32.const 0 i32.const 32 - i32.const 113 + i32.const 122 i32.const 0 call $~lib/builtins/abort unreachable @@ -2171,7 +2208,7 @@ if i32.const 0 i32.const 32 - i32.const 132 + i32.const 141 i32.const 0 call $~lib/builtins/abort unreachable @@ -2184,7 +2221,7 @@ if i32.const 0 i32.const 32 - i32.const 148 + i32.const 157 i32.const 0 call $~lib/builtins/abort unreachable @@ -2197,13 +2234,13 @@ if i32.const 0 i32.const 32 - i32.const 168 + i32.const 177 i32.const 0 call $~lib/builtins/abort unreachable end ) - (func $~start (; 32 ;) + (func $~start (; 33 ;) global.get $~started if return @@ -2213,10 +2250,10 @@ end call $start:while ) - (func $~lib/rt/pure/__collect (; 33 ;) + (func $~lib/rt/pure/__collect (; 34 ;) return ) - (func $~lib/rt/tlsf/freeBlock (; 34 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/freeBlock (; 35 ;) (param $0 i32) (param $1 i32) (local $2 i32) local.get $1 i32.load @@ -2232,7 +2269,7 @@ local.get $1 call $~lib/rt/rtrace/onfree ) - (func $~lib/rt/pure/decrement (; 35 ;) (param $0 i32) + (func $~lib/rt/pure/decrement (; 36 ;) (param $0 i32) (local $1 i32) (local $2 i32) local.get $0 @@ -2309,7 +2346,7 @@ i32.store offset=4 end ) - (func $~lib/rt/pure/__visit (; 36 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/pure/__visit (; 37 ;) (param $0 i32) (param $1 i32) local.get $0 global.get $~lib/heap/__heap_base i32.lt_u @@ -2333,7 +2370,7 @@ i32.sub call $~lib/rt/pure/decrement ) - (func $~lib/rt/__visit_members (; 37 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/__visit_members (; 38 ;) (param $0 i32) (param $1 i32) (local $2 i32) block $switch$1$default block $switch$1$case$4 From 3a23ba8cf8e53574da2043d3115b98b813737184 Mon Sep 17 00:00:00 2001 From: dcode Date: Mon, 2 Mar 2020 09:14:46 +0100 Subject: [PATCH 26/28] fix #1140 --- src/compiler.ts | 42 +++++++++++++----------- src/definitions.ts | 8 +++-- src/program.ts | 14 +++++++- tests/compiler/exportstar.json | 5 +++ tests/compiler/exportstar.optimized.wat | 35 ++++++++++++++++++++ tests/compiler/exportstar.ts | 1 + tests/compiler/exportstar.untouched.wat | 39 ++++++++++++++++++++++ tests/compiler/reexport.optimized.wat | 8 +++++ tests/compiler/reexport.ts | 3 ++ tests/compiler/reexport.untouched.wat | 8 +++++ tests/compiler/wasi-snapshot-preview1.ts | 2 +- 11 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 tests/compiler/exportstar.json create mode 100644 tests/compiler/exportstar.optimized.wat create mode 100644 tests/compiler/exportstar.ts create mode 100644 tests/compiler/exportstar.untouched.wat diff --git a/src/compiler.ts b/src/compiler.ts index f68012a6e6..e1fed340bf 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -85,7 +85,8 @@ import { PropertyPrototype, IndexSignature, File, - mangleInternalName + mangleInternalName, + Namespace } from "./program"; import { @@ -724,7 +725,6 @@ export class Compiler extends DiagnosticEmitter { // just traverse members below case ElementKind.ENUM: case ElementKind.NAMESPACE: - case ElementKind.FILE: case ElementKind.TYPEDEFINITION: case ElementKind.INDEXSIGNATURE: break; @@ -738,22 +738,24 @@ export class Compiler extends DiagnosticEmitter { ? INSTANCE_DELIMITER : STATIC_DELIMITER ); - if ( - element.kind == ElementKind.NAMESPACE || - element.kind == ElementKind.FILE - ) { - // for (let member of members.values()) { - for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { - let member = unchecked(_values[i]); - if (!member.is(CommonFlags.EXPORT)) continue; - this.ensureModuleExport(member.name, member, subPrefix); + if (element.kind == ElementKind.NAMESPACE) { + let implicitExport = element.is(CommonFlags.SCOPED); + // for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(members.get(memberName)); + if (implicitExport || member.is(CommonFlags.EXPORT)) { + this.ensureModuleExport(memberName, member, subPrefix); + } } } else { - // for (let member of members.values()) { - for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { - let member = unchecked(_values[i]); - if (member.is(CommonFlags.PRIVATE)) continue; - this.ensureModuleExport(member.name, member, subPrefix); + // for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(members.get(memberName)); + if (!member.is(CommonFlags.PRIVATE)) { + this.ensureModuleExport(memberName, member, subPrefix); + } } } } @@ -829,10 +831,10 @@ export class Compiler extends DiagnosticEmitter { this.compileElement(element); } } - var starExports = file.exportsStar; - if (starExports) { - for (let i = 0, k = starExports.length; i < k; ++i) { - let exportStar = unchecked(starExports[i]); + var exportsStar = file.exportsStar; + if (exportsStar) { + for (let i = 0, k = exportsStar.length; i < k; ++i) { + let exportStar = unchecked(exportsStar[i]); this.compileFile(exportStar); this.compileExports(exportStar); } diff --git a/src/definitions.ts b/src/definitions.ts index e5fa37dacc..f05dff48f1 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -409,7 +409,9 @@ export class TSDBuilder extends ExportsWalker { visitEnum(name: string, element: Enum): void { var sb = this.sb; indent(sb, this.indentLevel++); - sb.push("export enum "); + sb.push("export "); + if (element.is(CommonFlags.CONST)) sb.push("const "); + sb.push("enum "); sb.push(name); sb.push(" {\n"); var members = element.members; @@ -510,7 +512,9 @@ export class TSDBuilder extends ExportsWalker { // for (let member of instanceMembers.values()) { for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); - this.visitElement(member.name, member); + if (member.parent == element) { // own member + this.visitElement(member.name, member); + } } } indent(sb, --this.indentLevel); diff --git a/src/program.ts b/src/program.ts index 5d7f7a018a..eadd280a5e 100644 --- a/src/program.ts +++ b/src/program.ts @@ -2467,6 +2467,13 @@ export class File extends Element { var declaration = this.program.makeNativeNamespaceDeclaration(name); declaration.name = localIdentifier; var ns = new Namespace(name, parent, declaration); + ns.set(CommonFlags.SCOPED); + this.copyExportsToNamespace(ns); + return ns; + } + + /** Recursively copies the exports of this file to the specified namespace. */ + private copyExportsToNamespace(ns: Namespace): void { var exports = this.exports; if (exports) { // for (let [memberName, member] of exports) { @@ -2476,7 +2483,12 @@ export class File extends Element { ns.add(memberName, member); } } - return ns; + var exportsStar = this.exportsStar; + if (exportsStar) { + for (let i = 0, k = exportsStar.length; i < k; ++i) { + exportsStar[i].copyExportsToNamespace(ns); + } + } } } diff --git a/tests/compiler/exportstar.json b/tests/compiler/exportstar.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/exportstar.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/exportstar.optimized.wat b/tests/compiler/exportstar.optimized.wat new file mode 100644 index 0000000000..78eb99e6e5 --- /dev/null +++ b/tests/compiler/exportstar.optimized.wat @@ -0,0 +1,35 @@ +(module + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (type $none_=>_none (func)) + (memory $0 0) + (global $export/a i32 (i32.const 1)) + (global $export/b i32 (i32.const 2)) + (global $export/c i32 (i32.const 3)) + (export "memory" (memory $0)) + (export "add" (func $export/add)) + (export "sub" (func $export/sub)) + (export "renamed_mul" (func $export/mul)) + (export "a" (global $export/a)) + (export "b" (global $export/b)) + (export "renamed_c" (global $export/c)) + (export "ns.two" (func $export/ns.one)) + (export "default.two" (func $export/ns.one)) + (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.add + ) + (func $export/sub (; 1 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.sub + ) + (func $export/mul (; 2 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.mul + ) + (func $export/ns.one (; 3 ;) + nop + ) +) diff --git a/tests/compiler/exportstar.ts b/tests/compiler/exportstar.ts new file mode 100644 index 0000000000..ffea9c3cfe --- /dev/null +++ b/tests/compiler/exportstar.ts @@ -0,0 +1 @@ +export * from "./export"; diff --git a/tests/compiler/exportstar.untouched.wat b/tests/compiler/exportstar.untouched.wat new file mode 100644 index 0000000000..76fd31cf3f --- /dev/null +++ b/tests/compiler/exportstar.untouched.wat @@ -0,0 +1,39 @@ +(module + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (type $none_=>_none (func)) + (memory $0 0) + (table $0 1 funcref) + (global $export/a i32 (i32.const 1)) + (global $export/b i32 (i32.const 2)) + (global $export/c i32 (i32.const 3)) + (export "memory" (memory $0)) + (export "add" (func $export/add)) + (export "sub" (func $export/sub)) + (export "renamed_mul" (func $export/mul)) + (export "a" (global $export/a)) + (export "b" (global $export/b)) + (export "renamed_c" (global $export/c)) + (export "ns.two" (func $export/ns.two)) + (export "default.two" (func $export/ns.two)) + (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.add + ) + (func $export/sub (; 1 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.sub + ) + (func $export/mul (; 2 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.mul + ) + (func $export/ns.one (; 3 ;) + nop + ) + (func $export/ns.two (; 4 ;) + nop + ) +) diff --git a/tests/compiler/reexport.optimized.wat b/tests/compiler/reexport.optimized.wat index 2aa38298ec..ca01c6d093 100644 --- a/tests/compiler/reexport.optimized.wat +++ b/tests/compiler/reexport.optimized.wat @@ -17,6 +17,14 @@ (export "renamed_add" (func $export/add)) (export "rerenamed_sub" (func $export/mul)) (export "renamed_ns.two" (func $export/ns.one)) + (export "exportstar.add" (func $export/add)) + (export "exportstar.sub" (func $export/sub)) + (export "exportstar.renamed_mul" (func $export/mul)) + (export "exportstar.a" (global $export/a)) + (export "exportstar.b" (global $export/b)) + (export "exportstar.renamed_c" (global $export/c)) + (export "exportstar.ns.two" (func $export/ns.one)) + (export "exportstar.default.two" (func $export/ns.one)) (start $~start) (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) local.get $0 diff --git a/tests/compiler/reexport.ts b/tests/compiler/reexport.ts index c48dbf71ea..7b4f8172e4 100644 --- a/tests/compiler/reexport.ts +++ b/tests/compiler/reexport.ts @@ -24,3 +24,6 @@ export { imported_add(1, 2) + imported_sub(3, 4); export { ns as renamed_ns } from "./export"; + +import * as exportstar from "./exportstar"; +export { exportstar }; diff --git a/tests/compiler/reexport.untouched.wat b/tests/compiler/reexport.untouched.wat index 8c84f16753..19735a0f92 100644 --- a/tests/compiler/reexport.untouched.wat +++ b/tests/compiler/reexport.untouched.wat @@ -18,6 +18,14 @@ (export "renamed_add" (func $export/add)) (export "rerenamed_sub" (func $export/mul)) (export "renamed_ns.two" (func $export/ns.two)) + (export "exportstar.add" (func $export/add)) + (export "exportstar.sub" (func $export/sub)) + (export "exportstar.renamed_mul" (func $export/mul)) + (export "exportstar.a" (global $export/a)) + (export "exportstar.b" (global $export/b)) + (export "exportstar.renamed_c" (global $export/c)) + (export "exportstar.ns.two" (func $export/ns.two)) + (export "exportstar.default.two" (func $export/ns.two)) (start $~start) (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) local.get $0 diff --git a/tests/compiler/wasi-snapshot-preview1.ts b/tests/compiler/wasi-snapshot-preview1.ts index bc5ea71f7d..271f784475 100644 --- a/tests/compiler/wasi-snapshot-preview1.ts +++ b/tests/compiler/wasi-snapshot-preview1.ts @@ -8,7 +8,7 @@ import { subscription_fd_readwrite, signal, prestat_dir -} from "bindings/wasi_snapshot_preview1"; +} from "bindings/wasi"; import { Target } from "shared/target"; From b5b0d7672ff6d792ad268b329aed76697856f388 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 3 Mar 2020 01:55:14 +0100 Subject: [PATCH 27/28] abstract stubs, cleanup --- src/compiler.ts | 31 +++++++++++++++++++------------ src/definitions.ts | 16 ++++++++-------- src/parser.ts | 2 +- src/program.ts | 2 +- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index e1fed340bf..50614ec3c1 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -85,8 +85,7 @@ import { PropertyPrototype, IndexSignature, File, - mangleInternalName, - Namespace + mangleInternalName } from "./program"; import { @@ -1312,18 +1311,9 @@ export class Compiler extends DiagnosticEmitter { ); // imported function - } else { - if (!instance.is(CommonFlags.AMBIENT)) { - this.error( - DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, - instance.identifierNode.range - ); - } - + } else if (instance.is(CommonFlags.AMBIENT)) { instance.set(CommonFlags.MODULE_IMPORT); mangleImportName(instance, instance.declaration); // TODO: check for duplicates - - // create the import module.addFunctionImport( instance.internalName, mangleImportName_moduleName, @@ -1332,6 +1322,23 @@ export class Compiler extends DiagnosticEmitter { signature.nativeResults ); funcRef = module.getFunction(instance.internalName); + + // abstract function + } else if (instance.is(CommonFlags.ABSTRACT)) { + funcRef = module.addFunction( + instance.internalName, + signature.nativeParams, + signature.nativeResults, + null, + module.unreachable() + ); + this.virtualCalls.add(instance); + } else { + this.error( + DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, + instance.identifierNode.range + ); + funcRef = 0; // TODO? } instance.finalize(module, funcRef); diff --git a/src/definitions.ts b/src/definitions.ts index f05dff48f1..1ac48c5809 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -169,14 +169,14 @@ export abstract class ExportsWalker { assert(false); } - /* abstract */ visitGlobal(name: string, element: Global): void { unreachable(); } - /* abstract */ visitEnum(name: string, element: Enum): void { unreachable(); } - /* abstract */ visitFunction(name: string, element: Function): void { unreachable(); } - /* abstract */ visitClass(name: string, element: Class): void { unreachable(); } - /* abstract */ visitInterface(name: string, element: Interface): void { unreachable(); } - /* abstract */ visitField(name: string, element: Field): void { unreachable(); } - /* abstract */ visitNamespace(name: string, element: Element): void { unreachable(); } - /* abstract */ visitAlias(name: string, element: Element, originalName: string): void { unreachable(); } + abstract visitGlobal(name: string, element: Global): void; + abstract visitEnum(name: string, element: Enum): void; + abstract visitFunction(name: string, element: Function): void; + abstract visitClass(name: string, element: Class): void; + abstract visitInterface(name: string, element: Interface): void; + abstract visitField(name: string, element: Field): void; + abstract visitNamespace(name: string, element: Element): void; + abstract visitAlias(name: string, element: Element, originalName: string): void; } /** A WebIDL definitions builder. */ diff --git a/src/parser.ts b/src/parser.ts index 3fc4dcc4e6..7954e1bf0e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -2110,7 +2110,7 @@ export class Parser extends DiagnosticEmitter { } body = this.parseBlockStatement(tn, false); if (!body) return null; - } else if (!(flags & CommonFlags.AMBIENT) && !isInterface) { + } else if (!(flags & (CommonFlags.AMBIENT | CommonFlags.ABSTRACT)) && !isInterface) { this.error( DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range() diff --git a/src/program.ts b/src/program.ts index eadd280a5e..ef33042939 100644 --- a/src/program.ts +++ b/src/program.ts @@ -2214,7 +2214,7 @@ export abstract class Element { } /** Looks up the element with the specified name relative to this element, like in JS. */ - /* abstract */ lookup(name: string): Element | null { return unreachable(); } + abstract lookup(name: string): Element | null; /** Adds an element as a member of this one. Reports and returns `false` if a duplicate. */ add(name: string, element: DeclaredElement, localIdentifierIfImport: IdentifierExpression | null = null): bool { From febf1effb669ffe486ab3513fa857b923797b70e Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 3 Mar 2020 03:38:41 +0100 Subject: [PATCH 28/28] address review comments --- src/builtins.ts | 12 ++++++------ src/compiler.ts | 38 +++++++++++++++++++------------------- src/definitions.ts | 30 +++++++++++++++--------------- src/flow.ts | 4 ++-- src/glue/js/mapset.js | 18 +++--------------- src/index.ts | 6 +++--- src/module.ts | 2 +- src/program.ts | 26 +++++++++++++------------- src/resolver.ts | 6 +++--- src/util/collections.ts | 6 +++--- 10 files changed, 68 insertions(+), 80 deletions(-) diff --git a/src/builtins.ts b/src/builtins.ts index cde58ffaca..d6feedaf4a 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -7671,7 +7671,7 @@ export function compileVisitGlobals(compiler: Compiler): void { // this function is @lazy: make sure it exists compiler.compileFunction(visitInstance, true); - // for (let element of compiler.program.elementsByName.values()) { + // TODO: for (let element of compiler.program.elementsByName.values()) { for (let _values = Map_values(compiler.program.elementsByName), i = 0, k = _values.length; i < k; ++i) { let element = unchecked(_values[i]); if (element.kind != ElementKind.GLOBAL) continue; @@ -7753,7 +7753,7 @@ export function compileVisitMembers(compiler: Compiler): void { ); var lastId = 0; - // for (let [instanceId, instance] of managedClasses) { + // TODO: for (let [instanceId, instance] of managedClasses) { for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { let instanceId = _keys[i]; let instance = assert(managedClasses.get(instanceId)); @@ -7792,7 +7792,7 @@ export function compileVisitMembers(compiler: Compiler): void { } else { let members = instance.members; if (members) { - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), j = 0, l = _values.length; j < l; ++j) { let member = unchecked(_values[j]); if (member.kind == ElementKind.FIELD) { @@ -7829,7 +7829,7 @@ export function compileVisitMembers(compiler: Compiler): void { relooper.addBranchForSwitch(outer, block, [ instanceId ]); blocks.push(block); } - // for (let [instanceId, instance] of managedClasses) { + // TODO: for (let [instanceId, instance] of managedClasses) { for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { let instanceId = unchecked(_keys[i]); let instance = assert(managedClasses.get(instanceId)); @@ -7876,7 +7876,7 @@ export function compileRTTI(compiler: Compiler): void { var setPrototype = program.setPrototype; var mapPrototype = program.mapPrototype; var lastId = 0; - // for (let [instanceId, instance] of managedClasses) { + // TODO: for (let [instanceId, instance] of managedClasses) { for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { let instanceId = unchecked(_keys[i]); let instance = assert(managedClasses.get(instanceId)); @@ -7943,7 +7943,7 @@ export function compileClassInstanceOf(compiler: Compiler, prototype: ClassProto // if (__instanceof(ref, ID[i])) return true var instances = prototype.instances; if (instances !== null && instances.size > 0) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); stmts.push( diff --git a/src/compiler.ts b/src/compiler.ts index 50614ec3c1..197ed9d50d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -403,7 +403,7 @@ export class Compiler extends DiagnosticEmitter { // compile entry file(s) while traversing reachable elements var files = program.filesByName; - // for (let file of files.values()) { + // TODO: for (let file of files.values()) { for (let _values = Map_values(files), i = 0, k = _values.length; i < k; ++i) { let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) { @@ -443,7 +443,7 @@ export class Compiler extends DiagnosticEmitter { var cyclicClasses = program.findCyclicClasses(); if (cyclicClasses.size) { if (options.pedantic) { - // for (let classInstance of cyclicClasses) { + // TODO: for (let classInstance of cyclicClasses) { for (let _values = Set_values(cyclicClasses), i = 0, k = _values.length; i < k; ++i) { let classInstance = unchecked(_values[i]); this.pedantic( @@ -460,7 +460,7 @@ export class Compiler extends DiagnosticEmitter { var lazyLibraryFunctions = this.lazyLibraryFunctions; do { let functionsToCompile = new Array(); - // for (let instance of lazyLibraryFunctions) { + // TODO: for (let instance of lazyLibraryFunctions) { for (let _values = Set_values(lazyLibraryFunctions), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); functionsToCompile.push(instance); @@ -472,7 +472,7 @@ export class Compiler extends DiagnosticEmitter { } while (lazyLibraryFunctions.size); // compile pending class-specific instanceof helpers - // for (let prototype of this.pendingClassInstanceOf.values()) { + // TODO: for (let prototype of this.pendingClassInstanceOf.values()) { for (let _values = Set_values(this.pendingClassInstanceOf), i = 0, k = _values.length; i < k; ++i) { let prototype = unchecked(_values[i]); compileClassInstanceOf(this, prototype); @@ -553,7 +553,7 @@ export class Compiler extends DiagnosticEmitter { } // set up module exports - // for (let file of this.program.filesByName.values()) { + // TODO: for (let file of this.program.filesByName.values()) { for (let _values = Map_values(this.program.filesByName), i = 0, k = _values.length; i < k; ++i) { let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) this.ensureModuleExports(file); @@ -581,7 +581,7 @@ export class Compiler extends DiagnosticEmitter { } // Inject a virtual lookup table into each function potentially called virtually - /// for (let instance of virtualCalls.values()) { + // TODO: for (let instance of virtualCalls.values()) { for (let _values = Set_values(virtualCalls), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); this.warning( @@ -597,7 +597,7 @@ export class Compiler extends DiagnosticEmitter { private ensureModuleExports(file: File): void { var exports = file.exports; if (exports) { - // for (let [elementName, element] of exports) { + // TODO: for (let [elementName, element] of exports) { for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { let elementName = unchecked(_keys[i]); let element = assert(exports.get(elementName)); @@ -620,7 +620,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.FUNCTION_PROTOTYPE: { let instances = (element).instances; if (instances) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); let instanceName = name; @@ -636,7 +636,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.CLASS_PROTOTYPE: { let instances = (element).instances; if (instances) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); let instanceName = name; @@ -739,7 +739,7 @@ export class Compiler extends DiagnosticEmitter { ); if (element.kind == ElementKind.NAMESPACE) { let implicitExport = element.is(CommonFlags.SCOPED); - // for (let [memberName, member] of members) { + // TODO: for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(members.get(memberName)); @@ -748,7 +748,7 @@ export class Compiler extends DiagnosticEmitter { } } } else { - // for (let [memberName, member] of members) { + // TODO: for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(members.get(memberName)); @@ -811,7 +811,7 @@ export class Compiler extends DiagnosticEmitter { if (compileMembers) { let members = element.members; if (members) { - // for (let element of members.values()) { + // TODO: for (let element of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let element = unchecked(_values[i]); this.compileElement(element); @@ -824,7 +824,7 @@ export class Compiler extends DiagnosticEmitter { compileExports(file: File): void { var exports = file.exports; if (exports) { - // for (let element of exports.values()) { + // TODO: for (let element of exports.values()) { for (let _values = Map_values(exports), i = 0, k = _values.length; i < k; ++i) { let element = unchecked(_values[i]); this.compileElement(element); @@ -1129,7 +1129,7 @@ export class Compiler extends DiagnosticEmitter { var members = element.members; if (members) { - // for (let member of element.members.values()) { + // TODO: for (let member of element.members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) continue; // happens if an enum is also a namespace @@ -1463,7 +1463,7 @@ export class Compiler extends DiagnosticEmitter { var prototype = instance.prototype; var staticMembers = (prototype).members; if (staticMembers) { - // for (let element of staticMembers.values()) { + // TODO: for (let element of staticMembers.values()) { for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { let element = unchecked(_values[i]); switch (element.kind) { @@ -1500,7 +1500,7 @@ export class Compiler extends DiagnosticEmitter { if (ctorInstance) this.compileFunction(ctorInstance); var instanceMembers = instance.members; if (instanceMembers) { - // for (let element of instanceMembers.values()) { + // TODO: for (let element of instanceMembers.values()) { for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { let element = unchecked(_values[i]); switch (element.kind) { @@ -7124,7 +7124,7 @@ export class Compiler extends DiagnosticEmitter { var scopedLocals = flow.scopedLocals; if (scopedLocals) { let module = this.module; - // for (let local of scopedLocals.values()) { + // TODO: for (let local of scopedLocals.values()) { for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { let local = unchecked(_values[i]); if (local.is(CommonFlags.SCOPED)) { // otherwise an alias @@ -7198,7 +7198,7 @@ export class Compiler extends DiagnosticEmitter { while (parent = current.parent) current = parent; let scopedLocals = current.scopedLocals; if (scopedLocals) { - // for (let local of scopedLocals.values()) { + // TODO: for (let local of scopedLocals.values()) { for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { let local = unchecked(_values[i]); this.maybeFinishAutorelease(local, flow, stmts); @@ -9948,7 +9948,7 @@ export class Compiler extends DiagnosticEmitter { : 0; var nativeSizeType = this.options.nativeSizeType; - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); if ( diff --git a/src/definitions.ts b/src/definitions.ts index 1ac48c5809..239cc3c139 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -58,7 +58,7 @@ export abstract class ExportsWalker { /** Walks all elements and calls the respective handlers. */ walk(): void { - // for (let file of this.program.filesByName.values()) { + // TODO: for (let file of this.program.filesByName.values()) { for (let _values = Map_values(this.program.filesByName), i = 0, k = _values.length; i < k; ++i) { let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) this.visitFile(file); @@ -69,7 +69,7 @@ export abstract class ExportsWalker { visitFile(file: File): void { var exports = file.exports; if (exports) { - // for (let [memberName, member] of exports) { + // TODO: for (let [memberName, member] of exports) { for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(exports.get(memberName)); @@ -140,7 +140,7 @@ export abstract class ExportsWalker { private visitFunctionInstances(name: string, element: FunctionPrototype): void { var instances = element.instances; if (instances) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); if (instance.is(CommonFlags.COMPILED)) this.visitFunction(name, instance); @@ -151,7 +151,7 @@ export abstract class ExportsWalker { private visitClassInstances(name: string, element: ClassPrototype): void { var instances = element.instances; if (instances) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); if (instance.is(CommonFlags.COMPILED)) this.visitClass(name, instance); @@ -229,7 +229,7 @@ export class IDLBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - // for (let [memberName, member] of members) { + // TODO: for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(members.get(memberName)); @@ -249,7 +249,7 @@ export class IDLBuilder extends ExportsWalker { sb.push(";\n"); } } - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) this.visitElement(member.name, member); @@ -284,7 +284,7 @@ export class IDLBuilder extends ExportsWalker { sb.push("interface "); sb.push(element.name); sb.push(" {\n"); - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); this.visitElement(member.name, member); @@ -321,7 +321,7 @@ export class IDLBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); this.visitElement(member.name, member); @@ -418,7 +418,7 @@ export class TSDBuilder extends ExportsWalker { var remainingMembers = 0; if (members) { remainingMembers = members.size; - // for (let [memberName, member] of members) { + // TODO: for (let [memberName, member] of members) { for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(members.get(memberName)); @@ -501,7 +501,7 @@ export class TSDBuilder extends ExportsWalker { sb.push(" {\n"); var staticMembers = element.prototype.members; if (staticMembers) { - // for (let member of staticMembers.values()) { + // TODO: for (let member of staticMembers.values()) { for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); this.visitElement(member.name, member); @@ -509,7 +509,7 @@ export class TSDBuilder extends ExportsWalker { } var instanceMembers = element.members; if (instanceMembers) { - // for (let member of instanceMembers.values()) { + // TODO: for (let member of instanceMembers.values()) { for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); if (member.parent == element) { // own member @@ -546,7 +546,7 @@ export class TSDBuilder extends ExportsWalker { sb.push("export namespace "); sb.push(name); sb.push(" {\n"); - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); this.visitElement(member.name, member); @@ -632,14 +632,14 @@ export class TSDBuilder extends ExportsWalker { function hasCompiledMember(element: Element): bool { var members = element.members; if (members) { - // for (let member of members.values()) { + // TODO: for (let member of members.values()) { for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); switch (member.kind) { case ElementKind.FUNCTION_PROTOTYPE: { let instances = (member).instances; if (instances) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), j = 0, l = _values.length; j < l; ++j) { let instance = unchecked(_values[j]); if (instance.is(CommonFlags.COMPILED)) return true; @@ -650,7 +650,7 @@ function hasCompiledMember(element: Element): bool { case ElementKind.CLASS_PROTOTYPE: { let instances = (member).instances; if (instances) { - // for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { for (let _values = Map_values(instances), j = 0, l = _values.length; j < l; ++j) { let instance = unchecked(_values[j]); if (instance.is(CommonFlags.COMPILED)) return true; diff --git a/src/flow.ts b/src/flow.ts index 17a5afc206..5a1c8a2417 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -431,7 +431,7 @@ export class Flow { get hasScopedLocals(): bool { var scopedLocals = this.scopedLocals; if (scopedLocals) { - // for (let local of scopedLocals.values()) { + // TODO: for (let local of scopedLocals.values()) { for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { let local = unchecked(_values[i]); if (local.is(CommonFlags.SCOPED)) { // otherwise an alias @@ -446,7 +446,7 @@ export class Flow { freeScopedLocals(): void { var scopedLocals = this.scopedLocals; if (scopedLocals) { - // for (let local of scopedLocals.values()) { + // TODO: for (let local of scopedLocals.values()) { for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { let local = unchecked(_values[i]); if (local.is(CommonFlags.SCOPED)) { // otherwise an alias diff --git a/src/glue/js/mapset.js b/src/glue/js/mapset.js index 8dfbc667c7..3164caf25e 100644 --- a/src/glue/js/mapset.js +++ b/src/glue/js/mapset.js @@ -1,23 +1,11 @@ global.Map_keys = function(map) { - var keys = []; - for (let key of map.keys()) { - keys.push(key); - } - return keys; + return Array.from(map.keys()); }; global.Map_values = function(map) { - var vals = []; - for (let val of map.values()) { - vals.push(val); - } - return vals; + return Array.from(map.values()); }; global.Set_values = function(set) { - var vals = []; - for (let val of set.values()) { - vals.push(val); - } - return vals; + return Array.from(set.values()); }; diff --git a/src/index.ts b/src/index.ts index 338f81efcc..23bf8d6074 100644 --- a/src/index.ts +++ b/src/index.ts @@ -204,7 +204,7 @@ export function buildTSD(program: Program): string { export function buildRTTI(program: Program): string { var sb = new Array(); sb.push("{\n \"names\": [\n"); - // for (let cls of program.managedClasses.values()) { + // TODO: for (let cls of program.managedClasses.values()) { for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { let cls = unchecked(_values[i]); sb.push(" \""); @@ -212,7 +212,7 @@ export function buildRTTI(program: Program): string { sb.push("\",\n"); } sb.push(" ],\n \"base\": [\n"); - // for (let cls of program.managedClasses.values()) { + // TODO: for (let cls of program.managedClasses.values()) { for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { let cls = unchecked(_values[i]); let base = cls.base; @@ -221,7 +221,7 @@ export function buildRTTI(program: Program): string { sb.push(",\n"); } sb.push(" ],\n \"flags\": [\n"); - // for (let cls of program.managedClasses.values()) { + // TODO: for (let cls of program.managedClasses.values()) { for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { let cls = unchecked(_values[i]); sb.push(" "); diff --git a/src/module.ts b/src/module.ts index fa47ab3dde..3553a5b5a0 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1473,7 +1473,7 @@ export class Module { dispose(): void { assert(this.ref); - // for (let ptr of this.cachedStrings.values()) { + // TODO: for (let ptr of this.cachedStrings.values()) { for (let _values = Map_values(this.cachedStrings), i = 0, k = _values.length; i < k; ++i) { let ptr = unchecked(_values[i]); binaryen._free(ptr); diff --git a/src/program.ts b/src/program.ts index ef33042939..5b7f48c53e 100644 --- a/src/program.ts +++ b/src/program.ts @@ -774,7 +774,7 @@ export class Program extends DiagnosticEmitter { } // queued exports * should be linkable now that all files have been processed - // for (let [file, starExports] of queuedExportsStar) { + // TODO: for (let [file, starExports] of queuedExportsStar) { for (let _keys = Map_keys(queuedExportsStar), i = 0, k = _keys.length; i < k; ++i) { let file = _keys[i]; let starExports = assert(queuedExportsStar.get(file)); @@ -838,11 +838,11 @@ export class Program extends DiagnosticEmitter { } // queued exports should be resolvable now that imports are finalized - // for (let [file, exports] of queuedExports) { + // TODO: for (let [file, exports] of queuedExports) { for (let _keys = Map_keys(queuedExports), i = 0, k = _keys.length; i < k; ++i) { let file = unchecked(_keys[i]); let exports = assert(queuedExports.get(file)); - // for (let [exportName, queuedExport] of exports) { + // TODO: for (let [exportName, queuedExport] of exports) { for (let exportNames = Map_keys(exports), j = 0, l = exportNames.length; j < l; ++j) { let exportName = unchecked(exportNames[j]); let queuedExport = assert(exports.get(exportName)); @@ -960,7 +960,7 @@ export class Program extends DiagnosticEmitter { { let globalAliases = options.globalAliases; if (globalAliases) { - // for (let [alias, name] of globalAliases) { + // TODO: for (let [alias, name] of globalAliases) { for (let _keys = Map_keys(globalAliases), i = 0, k = _keys.length; i < k; ++i) { let alias = unchecked(_keys[i]); let name = assert(globalAliases.get(alias)); @@ -1000,7 +1000,7 @@ export class Program extends DiagnosticEmitter { this.allocArrayInstance = this.requireFunction(CommonNames.allocArray); // mark module exports, i.e. to apply proper wrapping behavior on the boundaries - // for (let file of this.filesByName.values()) { + // TODO: for (let file of this.filesByName.values()) { for (let _values = Map_values(this.filesByName), i = 0, k = _values.length; i < k; ++i) { let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) { @@ -1044,7 +1044,7 @@ export class Program extends DiagnosticEmitter { private markModuleExports(file: File): void { var exports = file.exports; if (exports) { - // for (let element of exports.values()) { + // TODO: for (let element of exports.values()) { for (let _values = Map_values(exports), j = 0, l = _values.length; j < l; ++j) { let element = unchecked(_values[j]); this.markModuleExport(element); @@ -1065,7 +1065,7 @@ export class Program extends DiagnosticEmitter { case ElementKind.CLASS_PROTOTYPE: { let instanceMembers = (element).instanceMembers; if (instanceMembers) { - // for (let member of instanceMembers.values()) { + // TODO: for (let member of instanceMembers.values()) { for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); this.markModuleExport(member); @@ -1087,7 +1087,7 @@ export class Program extends DiagnosticEmitter { } var staticMembers = element.members; if (staticMembers) { - // for (let member of staticMembers.values()) { + // TODO: for (let member of staticMembers.values()) { for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); this.markModuleExport(member); @@ -2047,7 +2047,7 @@ export class Program extends DiagnosticEmitter { /** Finds all cyclic classes. */ findCyclicClasses(): Set { var cyclics = new Set(); - // for (let instance of this.managedClasses.values()) { + // TODO: for (let instance of this.managedClasses.values()) { for (let _values = Map_values(this.managedClasses), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); if (!instance.isAcyclic) cyclics.add(instance); @@ -2476,7 +2476,7 @@ export class File extends Element { private copyExportsToNamespace(ns: Namespace): void { var exports = this.exports; if (exports) { - // for (let [memberName, member] of exports) { + // TODO: for (let [memberName, member] of exports) { for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(exports.get(memberName)); @@ -3538,7 +3538,7 @@ export class Class extends TypedElement { var inheritedTypeArguments = base.contextualTypeArguments; if (inheritedTypeArguments) { let contextualTypeArguments = this.contextualTypeArguments; - // for (let [baseName, baseType] of inheritedTypeArguments) { + // TODO: for (let [baseName, baseType] of inheritedTypeArguments) { for (let _keys = Map_keys(inheritedTypeArguments), i = 0, k = _keys.length; i < k; ++i) { let baseName = unchecked(_keys[i]); let baseType = assert(inheritedTypeArguments.get(baseName)); @@ -3718,7 +3718,7 @@ export class Class extends TypedElement { var current: Class | null; var instanceMembers = this.members; if (instanceMembers) { - // for (let member of instanceMembers.values()) { + // TODO: for (let member of instanceMembers.values()) { for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); if (member.kind == ElementKind.FIELD) { @@ -3932,7 +3932,7 @@ function copyMembers(src: Element, dest: Element): void { if (srcMembers) { let destMembers = dest.members; if (!destMembers) dest.members = destMembers = new Map(); - // for (let [memberName, member] of srcMembers) { + // TODO: for (let [memberName, member] of srcMembers) { for (let _keys = Map_keys(srcMembers), i = 0, k = _keys.length; i < k; ++i) { let memberName = unchecked(_keys[i]); let member = assert(srcMembers.get(memberName)); diff --git a/src/resolver.ts b/src/resolver.ts index cb657ae5fd..1843cb9e34 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2930,7 +2930,7 @@ export class Resolver extends DiagnosticEmitter { assert(!pendingClasses.includes(base)); let baseMembers = base.members; if (baseMembers) { - // for (let [baseMemberName, baseMember] of baseMembers) { + // TODO: for (let [baseMemberName, baseMember] of baseMembers) { for (let _keys = Map_keys(baseMembers), i = 0, k = _keys.length; i < k; ++i) { let baseMemberName = unchecked(_keys[i]); let baseMember = assert(baseMembers.get(baseMemberName)); @@ -2944,7 +2944,7 @@ export class Resolver extends DiagnosticEmitter { var prototype = instance.prototype; var instanceMemberPrototypes = prototype.instanceMembers; if (instanceMemberPrototypes) { - // for (let member of instanceMemberPrototypes.values()) { + // TODO: for (let member of instanceMemberPrototypes.values()) { for (let _values = Map_values(instanceMemberPrototypes), i = 0, k = _values.length; i < k; ++i) { let member = unchecked(_values[i]); switch (member.kind) { @@ -3054,7 +3054,7 @@ export class Resolver extends DiagnosticEmitter { // Fully resolve operator overloads (don't have type parameters on their own) var overloadPrototypes = prototype.overloadPrototypes; - // for (let [overloadKind, overloadPrototype] of overloadPrototypes) { + // TODO: for (let [overloadKind, overloadPrototype] of overloadPrototypes) { for (let _keys = Map_keys(overloadPrototypes), i = 0, k = _keys.length; i < k; ++i) { let overloadKind = unchecked(_keys[i]); let overloadPrototype = assert(overloadPrototypes.get(overloadKind)); diff --git a/src/util/collections.ts b/src/util/collections.ts index fb107d7e6c..f1ea2461fb 100644 --- a/src/util/collections.ts +++ b/src/util/collections.ts @@ -11,7 +11,7 @@ export function makeArray(original: Array | null = null): Array { export function makeSet(original: Set | null = null): Set { if (original) { let cloned = new Set(); - // for (let v of original) { + // TODO: for (let v of original) { for (let _values = Set_values(original), i = 0, k = _values.length; i < k; ++i) { let v = unchecked(_values[i]); cloned.add(v); @@ -24,7 +24,7 @@ export function makeSet(original: Set | null = null): Set { export function makeMap(original: Map | null = null, overrides: Map | null = null): Map { var cloned = new Map(); if (original) { - // for (let [k, v] of original) { + // TODO: for (let [k, v] of original) { for (let _keys = Map_keys(original), i = 0, k = _keys.length; i < k; ++i) { let k = unchecked(_keys[i]); let v = assert(original.get(k)); @@ -32,7 +32,7 @@ export function makeMap(original: Map | null = null, overrides: Map