Reinventing the wheel. Again. But with a notch.

WebAssembly runs in a sandbox, making its environment more limited than a usual browser environment. AssemblyScript tries to fill the gaps by reimplementing commonly known functionality, besides providing direct access to WebAssembly instructions through built-ins.

AssemblyScript comes with its own standard library very much resembling what developers became used to when writing JavaScript.

Depending on how (fast) the relevant WebAssembly specifications for reference types, WebIDL bindings and GC develop, there might be additional features in the future, like importing parts of the standard library from the host. Additional rather low-level WebAssembly functionality that the standard library makes extensive use of is described below.

By making use of statically evaluated type checks, especially in generic contexts, untaken branches can be eliminated statically, leading to concrete WebAssembly functions that handle one type specificially.

**isInteger**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression is of an integer type and not a reference. Compiles to a constant.**isFloat**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression is of a float type. Compiles to a constant.**isSigned**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression can represent negative numbers. Compiles to a constant.**isReference**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression is of a reference type. Compiles to a constant.**isString**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression can be used as a string. Compiles to a constant.**isArray**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression can be used as an array. Compiles to a constant.**isFunction**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression is of a function type. Compiles to a constant.**isNullable**<`T`

>(value?:`T`

):`bool`

Tests if the specified type*or*expression is of a nullable reference type. Compiles to a constant.**isDefined**(expression:`*`

):`bool`

Tests if the specified expression resolves to a defined element. Compiles to a constant.**isConstant**(expression:`*`

):`bool`

Tests if the specified expression evaluates to a constant value. Compiles to a constant.**isManaged**<`T`

>(expression:`*`

):`bool`

Tests if the specified type*or*expression is of a managed type. Compiles to a constant. Usually only relevant when implementing custom collection-like classes.

function add<T>(a: T, b: T): T {return a + b; // addition if numeric, string concatenation if a string}â€‹function add<T>(a: T, b: T): T {if (isString<T>()) { // eliminated if T is not a stringreturn parseInt(a) + parseInt(b);} else { // eliminated if T is a stringreturn a + b;}}

If you are not going to use low-level WebAssembly in the foreseeable future, feel free to come back to the following paragraphs at a later time and continue at the next page right away.

**sizeof**<`T`

>():`usize`

Determines the byte size of the respective*basic type*. Means: If`T`

is a class type, the size of`usize`

is returned. To obtain the size of a class in memory, use`offsetof<T>()`

instead. Compiles to a constant.**offsetof**<`T`

>(fieldName?:`string`

):`usize`

Determines the offset of the specified field within the given class type. Returns the class type's end offset (means: where the next field would be located, before alignment) if field name has been omitted. Compiles to a constant. The`fieldName`

argument must be a compile-time constant`string`

because there is no information about field names anymore in the final binary. Hence, the field's name must be known at the time the returned constant is computed.**alignof**<`T`

>():`usize`

Determines the alignment (log2) of the specified underlying*basic type*. Means: If`T`

is a class type, the alignment of`usize`

is returned. Compiles to a constant.

**assert**<`T`

>(isTrueish:`T`

, message?:`string`

):`T`

Traps if the specified value is not true-ish, otherwise returns the non-nullable value. Like assertions in C, aborting the entire program if the expectation fails, with the`--noAssert`

option to disable all assertions in production.**instantiate**<`T`

>(...args:`*[]`

):`T`

Instantiates a new instance of`T`

using the specified constructor arguments.**changetype**<`T`

>(value:`*`

):`T`

Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa.**idof**<`T`

>():`u32`

Obtains the computed unique id of a class type. Usually only relevant when allocating objects or dealing with RTTI externally.

The following generic built-ins compile to WebAssembly instructions directly.

**clz**<`T = i32 | i64`

>(value:`T`

):`T`

Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero.**ctz**<`T = i32 | i64`

>(value:`T`

):`T`

Performs the sign-agnostic count tailing zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered trailing if the value is zero.**popcnt**<`T = i32 | i64`

>(value:`T`

):`T`

Performs the sign-agnostic count number of one bits operation on a 32-bit or 64-bit integer.**rotl**<`T = i32 | i64`

>(value:`T`

, shift:`T`

):`T`

Performs the sign-agnostic rotate left operation on a 32-bit or 64-bit integer.**rotr**<`T = i32 | i64`

>(value:`T`

, shift:`T`

):`T`

Performs the sign-agnostic rotate right operation on a 32-bit or 64-bit integer.**abs**<`T = i32 | i64 | f32 | f64`

>(value:`T`

):`T`

Computes the absolute value of an integer or float.**max**<`T = i32 | i64 | f32 | f64`

>(left:`T`

, right:`T`

):`T`

Determines the maximum of two integers or floats. If either operand is`NaN`

, returns`NaN`

.**min**<`T = i32 | i64 | f32 | f64`

>(left:`T`

, right:`T`

):`T`

Determines the minimum of two integers or floats. If either operand is`NaN`

, returns`NaN`

.**ceil**<`T = f32 | f64`

>(value:`T`

):`T`

Performs the ceiling operation on a 32-bit or 64-bit float.**floor**<`T = f32 | f64`

>(value:`T`

):`T`

Performs the floor operation on a 32-bit or 64-bit float.**copysign**<`T = f32 | f64`

>(x:`T`

, y:`T`

):`T`

Composes a 32-bit or 64-bit float from the magnitude of`x`

and the sign of`y`

.**nearest**<`T = f32 | f64`

>(value:`T`

):`T`

Rounds to the nearest integer tied to even of a 32-bit or 64-bit float.**reinterpret**<`T = i32 | i64 | f32 | f64`

>(value:`*`

):`T`

Reinterprets the bits of the specified value as type`T`

. Valid reinterpretations are u32/i32 to/from f32 and u64/i64 to/from f64.**sqrt**<`T = f32 | f64`

>(value:`T`

):`T`

Calculates the square root of a 32-bit or 64-bit float.**trunc**<`T = f32 | f64`

>(value:`T`

):`T`

Rounds to the nearest integer towards zero of a 32-bit or 64-bit float.

Similarly, the following built-ins emit WebAssembly instructions accessing or otherwise modifying memory.

**load**<`T`

>(ptr:`usize`

, immOffset?:`usize`

):`T`

Loads a value of the specified type from memory. Equivalent to dereferencing a pointer in other languages.**store**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`void`

Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value.**memory.size**():`i32`

Returns the current size of the memory in units of pages. One page is 64kb.**memory.grow**(value:`i32`

):`i32`

Grows linear memory by a given unsigned delta of pages. One page is 64kb. Returns the previous size of the memory in units of pages or`-1`

on failure.**Note**that calling`memory.grow`

where a memory manager is present might break it.**memory.copy**(dst:`usize`

, src:`usize`

, n:`usize`

):`void`

Copies`n`

bytes from`src`

to`dst`

. Regions may overlap. Emits the respective instruction if bulk-memory is enabled, otherwise ships a polyfill.**memory.fill**(dst:`usize`

, value:`u8`

, n:`usize`

):`void`

Fills`n`

bytes at`dst`

with the given byte`value`

. Emits the respective instruction if bulk-memory is enabled, otherwise ships a polyfill.

The `immOffset`

argument is a bit special here, because it becomes an actual immediate of the respective WebAssembly instruction instead of a normal operand. Thus it must be provided as a compile time constant value. This can be a literal or the value of a `const`

variable that the compiler can precompute.

Sign-agnostic endian conversions (reverse bytes).

**bswap**<`T`

>(value:`T`

):`T`

Reverse all bytes for

,**8-bit**,**16-bit**and**32-bit**integers.*64-bit***bswap16**<`T`

>(value:`T`

):`T`

Reverse only last 2 bytes regardless of the type of argument.

â€‹

**select**<`T`

>(ifTrue:`T`

, ifFalse:`T`

, condition:`bool`

):`T`

Selects one of two pre-evaluated values depending on the condition. Differs from an`if/else`

in that both arms are always executed and the final value is picked based on the condition afterwards. Performs better than an`if/else`

only if the condition is random (means: branch prediction is not going to perform well) and both alternatives are cheap. It is also worth to note that Binaryen will do relevant optimizations like switching to a`select`

automatically, so using a ternary`? :`

for example is just fine.**unreachable**():`*`

Emits an unreachable instruction that results in a runtime error (trap) when executed. Both a statement and an expression of any type. Beware that trapping in managed code will most likely lead to memory leaks or even break the program because it ends execution prematurely.

**call_indirect**<`T`

>(target:`u32`

, ...args:`*[]`

):`T`

Emits a`call_indirect`

instruction, calling the specified function in the function table by index with the specified arguments. Does result in a runtime error if the arguments do not match the called function.

The following instructions represent the WebAssembly threads and atomics specification. Must be enabled with `--enable threads`

.

atomic.

**load**<`T`

>(offset:`usize`

, immOffset?:`usize`

):`T`

Atomically loads an integer value from memory and returns it.atomic.

**store**<`T`

>(offset:`usize`

, value:`T`

, immOffset?:`usize`

):`void`

Atomically stores an integer value to memory.atomic.

**add**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`T`

Atomically adds an integer value in memory.atomic.

**sub**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`T`

Atomically subtracts an integer value in memory.atomic.

**and**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`T`

Atomically performs a bitwise AND operation on an integer value in memory.atomic.

**or**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`T`

Atomically performs a bitwise OR operation on an integer value in memory.atomic.

**xor**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`T`

Atomically performs a bitwise XOR operation on an integer value in memory.atomic.

**xchg**<`T`

>(ptr:`usize`

, value:`T`

, immOffset?:`usize`

):`T`

Atomically exchanges an integer value in memory.atomic.

**cmpxchg**<`T`

>(ptr:`usize`

, expected:`T`

, replacement:`T`

, immOffset?:`usize`

):`T`

Atomically compares and exchanges an integer value in memory if the condition is met.atomic.

**wait**<`T`

>(ptr:`usize`

, expected:`T`

, timeout:`i64`

):`AtomicWaitResult`

Performs a wait operation on an address in memory suspending this agent if the integer condition is met. Return values areValue

Description

0

OK: Woken by another agent.

1

NOT_EQUAL: Loaded value did not match the expected value.

2

TIMED_OUT: Not woken before the timeout expired.

atomic.

**notify**(ptr:`usize`

, count:`i32`

):`i32`

Performs a notify operation on an address in memory waking up suspended agents.atomic.

**fence**():`void`

Performs a fence operation, preserving synchronization guarantees of higher level languages.

Again, the `immOffset`

argument must be a compile time constant value.

Likewise, these represent the WebAssembly SIMD specification. Must be enabled with `--enable simd`

.

**v128**(a:`i8`

, ... , p:`i8`

):`v128`

Initializes a 128-bit vector from sixteen 8-bit integer values. Arguments must be compile-time constants.v128.

**splat**<`T`

>(x:`T`

):`v128`

Creates a 128-bit vector with identical lanes.v128.

**extract_lane**<`T`

>(x:`v128`

, idx:`u8`

):`T`

Extracts one lane from a 128-bit vector as a scalar.v128.

**replace_lane**<`T`

>(x:`v128`

, idx:`u8`

, value:`T`

):`v128`

Replaces one lane in a 128-bit vector.v128.

**shuffle**<`T`

>(a:`v128`

, b:`v128`

, ...lanes:`u8[]`

):`v128`

Selects lanes from either 128-bit vector according to the specified lane indexes.v128.

**load**(offset:`usize`

, immOffset?:`usize`

, immAlign?:`usize`

):`v128`

Loads a 128-bit vector from memory.v128.

**store**(offset:`usize`

, value:`v128`

, immOffset?:`usize`

, immAlign?:`usize`

):`void`

Stores a 128-bit vector to memory.v128.

**add**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Adds each lane of two 128-bit vectors.v128.

**sub**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Subtracts each lane of two 128-bit vectors.v128.

**mul**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Multiplies each lane of two 128-bit vectors.v128.

**div**<`T`

>(a:`v128`

, b:`v128`

):`v128`

*float only*Divides each lane of two 128-bit vectors.v128.

**neg**<`T`

>(a:`v128`

):`v128`

Negates each lane of a 128-bit vector.v128.

**add_saturate**<`T`

>(a:`v128`

, b:`v128`

):`v128`

*i8/i16 only*Adds each lane of two 128-bit vectors using saturation.

v128.

**sub_saturate**<`T`

>(a:`v128`

, b:`v128`

):`v128`

*i8/i16 only*Subtracts each lane of two 128-bit vectors using saturation.

v128.

**shl**<`T`

>(a:`v128`

, b:`i32`

):`v128`

*integer only*Performs a bitwise left shift on each lane of a 128-bit vector by a scalar.

v128.

**shr**<`T`

>(a:`v128`

, b:`i32`

):`v128`

*integer only*Performs a bitwise right shift on each lane of a 128-bit vector by a scalar.

v128.

**and**(a:`v128`

, b:`v128`

):`v128`

*integer only*Performs the bitwise AND operation on each lane of two 128-bit vectors.

v128.

**or**(a:`v128`

, b:`v128`

):`v128`

*integer only*Performs the bitwise OR operation on each lane of two 128-bit vectors.

v128.

**xor**(a:`v128`

, b:`v128`

):`v128`

*integer only*Performs the bitwise XOR operation on each lane of two 128-bit vectors.

v128.

**not**(a:`v128`

):`v128`

*integer only*Performs the bitwise NOT operation on each lane of a 128-bit vector.

v128.

**bitselect**(a:`v128`

, b:`v128`

, mask:`v128`

):`v128`

Selects bits of either 128-bit vector according to the specified mask.

v128.

**any_true**<`T`

>(a:`v128`

):`bool`

Reduces a 128-bit vector to a scalar indicating whether any lane is considered`true`

.v128.

**all_true**<`T`

>(a:`v128`

):`bool`

Reduces a 128-bit vector to a scalar indicating whether all lanes are considered`true`

.v128.

**max**<`T`

>(a:`v128`

, b:`v128`

):`v128`

*float only*Computes the maximum of each lane of two 128-bit vectors.v128.

**min**<`T`

>(a:`v128`

, b:`v128`

):`v128`

*float only*Computes the minimum of each lane of two 128-bit vectors.v128.

**abs**<`T`

>(a:`v128`

):`v128`

*float only*Computes the absolute value of each lane of a 128-bit vector.v128.

**sqrt**<`T`

>(a:`v128`

):`v128`

*float only*Computes the square root of each lane of a 128-bit vector.v128.

**eq**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Computes which lanes of two 128-bit vectors are equal.v128.

**ne**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Computes which lanes of two 128-bit vectors are not equal.v128.

**lt**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Computes which lanes of the first 128-bit vector are less than those of the second.v128.

**le**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Computes which lanes of the first 128-bit vector are less than or equal those of the second.v128.

**gt**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Computes which lanes of the first 128-bit vector are greater than those of the second.v128.

**ge**<`T`

>(a:`v128`

, b:`v128`

):`v128`

Computes which lanes of the first 128-bit vector are greater than or equal those of the second.v128.

**convert**<`TFrom`

>(a:`v128`

):`v128`

*integer only*Converts each lane of a 128-bit vector from integer to floating point.v128.

**trunc**<`TTo`

>(a:`v128`

):`v128`

*float only*Truncates each lane of a 128-bit vector from floating point to integer with saturation.v128.

**qfma**<`T`

>(a:`v128`

, b:`v128`

, c:`v128`

):`v128`

*float only*Computes`(a * b) + c`

for each lane of the given 128-bit vectors.v128.

**qfms**<`T`

>(a:`v128`

, b:`v128`

, c:`v128`

):`v128`

*float only*Computes`(a * b) - c`

for each lane of the given 128-bit vectors.

In addition, the namespaces `i8x16`

, `i16x8`

, `i32x4`

, `i64x2`

, `f32x4`

and `f64x2`

provide their respective non-generic instructions, like `i32x4.splat`

etc. Each of them can also be used to create a literal directly:

**i8x16**(a:`i8`

, ... , p:`i8`

):`v128`

Initializes a 128-bit vector from sixteen 8-bit integer values. Arguments must be compile-time constants.**i16x8**(a:`i16`

, ..., h:`i16`

):`v128`

Initializes a 128-bit vector from eight 16-bit integer values. Arguments must be compile-time constants.**i32x4**(a:`i32`

, b:`i32`

, c:`i32`

, d:`i32`

):`v128`

Initializes a 128-bit vector from four 32-bit integer values. Arguments must be compile-time constants.**i64x2**(a:`i64`

, b:`i64`

):`v128`

Initializes a 128-bit vector from two 64-bit integer values. Arguments must be compile-time constants.**f32x4**(a:`f32`

, b:`f32`

, c:`f32`

, d:`f32`

):`v128`

Initializes a 128-bit vector from four 32-bit float values. Arguments must be compile-time constants.**f64x2**(a:`f64`

, b:`f64`

):`v128`

Initializes a 128-bit vector from two 64-bit float values. Arguments must be compile-time constants.