Skip to content

Built ins

Daniel Wirtz edited this page May 26, 2019 · 9 revisions

To provide direct (compile to opcode) access to native WebAssembly operations, the following functions plus a few TS/JS-like constants are provided in the global scope:

Context-sensitive constants

  • NaN: f32 | f64
    NaN (not a number) as a 32-bit or 64-bit float depending on context. Compiles to a constant.

  • Infinity: f32 | f64
    Positive infinity as a 32-bit or 64-bit float depending on context. Compiles to a constant.

Compile-time type checks

  • 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.

  • sizeof<T>(): usize
    Determines the byte size of the specified core or class type. 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 core type. Compiles to a constant.

  • idof<T>(): u32
    Obtains the computed unique id of a class type. Usually only relevant when allocating objects or dealing with RTTI externally.

Note that whenever the compiler spots a constant condition, it will automatically eliminate untaken branches and not attempt to compile them. For example, if a generic function is intended to work with both integers and strings with just a few statements differing, a compile-time type check with a constant condition on an if-then-else statement can be utilized to make it behave differently in parts depending on the actual type argument:

function doSomething<T>(a: T): T {
  if (isString<T>()) {
    ... // eliminated if T is not a string
  } else {
    ... // eliminated if T is a string
  }
}

Math

  • isNaN<T = f32 | f64>(value: T): bool
    Tests if a 32-bit or 64-bit float is NaN.

  • isFinite<T = f32 | f64>(value: T): bool
    Tests if a 32-bit or 64-bit float is finite, that is not NaN or +/-Infinity.

  • 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.

Memory access

  • 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.

Note that imm* arguments must be compile-time constants (const global or local) because these are immediates of the respective instruction. For example, an i32.load instruction's offset is a value within the instruction itself and its concrete value must be known when the instruction is emitted.

Atomics 🦄

Must be supported by the host and 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 are

    Value 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.

See notes on imm* arguments in the Memory access section above.

Control flow

  • select<T>(ifTrue: T, ifFalse: T, condition: bool): T
    Selects one of two pre-evaluated values depending on the condition.

  • unreachable(): *
    Emits an unreachable operation that results in a runtime error when executed. Both a statement and an expression of any type.

Host operations

  • 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.

Other

  • parseInt(str: string, radix?: i32): i64
    Parses a string to a 64-bit integer. Returns 0 on invalid inputs unlike NaN in JS.

  • parseFloat(str: string): f64
    Parses a string to a 64-bit float. Returns NaN on invalid inputs.

  • 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.

  • assert<T>(isTrueish: T, message?: string): T
    Traps if the specified value is not true-ish, otherwise returns the non-nullable value.

  • unchecked(expr: *): *
    Explicitly requests no bounds checks on the provided expression. Useful for array accesses.

  • 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.

  • instantiate<T>(...args: *[]): T
    Instantiates a new instance of T using the specified constructor arguments.

Decorators

The following WebAssembly-specific operators can be used to annotate non-TS behavior:

  • @global
    Adds an element to the global scope.

  • @inline
    Forces inlining of a function.

  • @external([moduleName: string,] elementName: string)
    Changes the external name of a declared global or function.

  • @operator(token: string)
    Annotates a binary operator overload.

    • @operator.binary(token: string)
      Same as @operator.

    • @operator.prefix(token: string)
      Annotates a unary prefix operator overload.

    • @operator.postfix(token: string)
      Annotates a unary postfix operator overload.

 

Clone this wiki locally