Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/src/utils/warnings.re
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,11 @@ let message =
| PrintUnsafe(typ) =>
"it looks like you are using `print` on an unsafe Wasm value here.\nThis is generally unsafe and will cause errors. Use `DebugPrint.print`"
++ typ
++ " from the `runtime/debugPrint` module instead."
++ " from the `runtime/unsafe/debugPrint` module instead."
| ToStringUnsafe(typ) =>
"it looks like you are using `toString` on an unsafe Wasm value here.\nThis is generally unsafe and will cause errors. Use `DebugPrint.toString`"
++ typ
++ " from the `runtime/debugPrint` module instead."
++ " from the `runtime/unsafe/debugPrint` module instead."
| ArrayIndexNonInteger(idx) =>
"Array index should be an integer, but found `" ++ idx ++ "`."
| PrintUnsafeRef => "it looks like you are using `print` on a `WasmRef` value here.\nThis is generally unsafe and will cause errors."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,47 @@ basic functionality › unsafe_wasm_globals
(mimp_type (MGlobalImport (WasmValue WasmF64) true))
(mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1082) (name printF64)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printF64)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printF64)
(mimp_type (MFuncImport (GrainValue (WasmValue WasmF64)) (GrainValue)))
(mimp_kind MImportGrain) (mimp_setup MSetupNone) (mimp_used true))
((mimp_id ((stamp 1082) (name printF64)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printF64)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printF64)
(mimp_type (MGlobalImport GrainValue true)) (mimp_kind MImportGrain)
(mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1081) (name _F32_VAL)))
(mimp_mod unsafeWasmGlobalsExports.gr) (mimp_name _F32_VAL)
(mimp_type (MGlobalImport (WasmValue WasmF32) true))
(mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1080) (name printF32)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printF32)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printF32)
(mimp_type (MFuncImport (GrainValue (WasmValue WasmF32)) (GrainValue)))
(mimp_kind MImportGrain) (mimp_setup MSetupNone) (mimp_used true))
((mimp_id ((stamp 1080) (name printF32)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printF32)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printF32)
(mimp_type (MGlobalImport GrainValue true)) (mimp_kind MImportGrain)
(mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1079) (name _I64_VAL)))
(mimp_mod unsafeWasmGlobalsExports.gr) (mimp_name _I64_VAL)
(mimp_type (MGlobalImport (WasmValue WasmI64) true))
(mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1078) (name printI64)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printI64)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printI64)
(mimp_type (MFuncImport (GrainValue (WasmValue WasmI64)) (GrainValue)))
(mimp_kind MImportGrain) (mimp_setup MSetupNone) (mimp_used true))
((mimp_id ((stamp 1078) (name printI64)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printI64)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printI64)
(mimp_type (MGlobalImport GrainValue true)) (mimp_kind MImportGrain)
(mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1077) (name _I32_VAL)))
(mimp_mod unsafeWasmGlobalsExports.gr) (mimp_name _I32_VAL)
(mimp_type (MGlobalImport (WasmValue WasmI32) true))
(mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true))
((mimp_id ((stamp 1076) (name printI32)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printI32)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printI32)
(mimp_type (MFuncImport (GrainValue (WasmValue WasmI32)) (GrainValue)))
(mimp_kind MImportGrain) (mimp_setup MSetupNone) (mimp_used true))
((mimp_id ((stamp 1076) (name printI32)))
(mimp_mod runtime/debugPrint.gr) (mimp_name printI32)
(mimp_mod runtime/unsafe/debugPrint.gr) (mimp_name printI32)
(mimp_type (MGlobalImport GrainValue true)) (mimp_kind MImportGrain)
(mimp_setup MCallGetter) (mimp_used true))))
(exports ())
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/input/letMutForLoop.gr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module LetMutForLoop

from "runtime/unsafe/wasmi64" include WasmI64
from "runtime/debugPrint" include DebugPrint
from "runtime/unsafe/debugPrint" include DebugPrint

@unsafe
let foo = () => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/input/unsafeWasmGlobals.gr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module UnsafeWasmGlobals

from "runtime/debugPrint" include DebugPrint
from "runtime/unsafe/debugPrint" include DebugPrint

from "unsafeWasmGlobalsExports" include UnsafeWasmGlobalsExports
use UnsafeWasmGlobalsExports.{ _I32_VAL, _I64_VAL, _F32_VAL, _F64_VAL }
Expand Down
6 changes: 3 additions & 3 deletions compiler/test/runtime/unsafe/wasmf32.test.gr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module WasmF32Test

from "runtime/unsafe/wasmf32" include WasmF32
from "runtime/unsafe/conv" include Conv
from "runtime/unsafe/dataStructures" include DataStructures as DS

@unsafe
let test = () => {
Expand Down Expand Up @@ -57,8 +57,8 @@ let test = () => {
assert WasmF32.demoteF64(1.23W) == 1.23w

// Grain conversion tests
assert Conv.fromFloat32(1.23f) == 1.23w
assert eq(Conv.toFloat32(1.23w), 1.23f)
assert DS.Float32.fromFloat32(1.23f) == 1.23w
assert eq(DS.Float32.toFloat32(1.23w), 1.23f)
}

test()
6 changes: 3 additions & 3 deletions compiler/test/runtime/unsafe/wasmf64.test.gr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module WasmF64Test

from "runtime/unsafe/wasmf64" include WasmF64
from "runtime/unsafe/conv" include Conv
from "runtime/unsafe/dataStructures" include DataStructures as DS

@unsafe
let test = () => {
Expand Down Expand Up @@ -57,8 +57,8 @@ let test = () => {
assert WasmF64.promoteF32(1.5w) == 1.5W

// Grain conversion tests
assert eq(Conv.toFloat64(1.23W), 1.23d)
assert Conv.fromFloat64(1.23d) == 1.23W
assert eq(DS.Float64.toFloat64(1.23W), 1.23d)
assert DS.Float64.fromFloat64(1.23d) == 1.23W
}

test()
22 changes: 11 additions & 11 deletions compiler/test/runtime/unsafe/wasmi32.test.gr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module WasmI32Test

from "runtime/unsafe/wasmi32" include WasmI32
from "runtime/unsafe/conv" include Conv
from "runtime/unsafe/dataStructures" include DataStructures as DS

@unsafe
let test = () => {
Expand Down Expand Up @@ -85,27 +85,27 @@ let test = () => {
assert WasmI32.extendS16(0x8000n) == 0xffff8000n

// Grain conversion tests
assert eq(Conv.toInt32(45n), 45l)
assert eq(DS.Int32.toInt32(45n), 45l)

assert Conv.fromInt32(45l) == 45n
assert DS.Int32.fromInt32(45l) == 45n

// within range of simple numbers
assert eq(Conv.wasmI32ToNumber(45n), 45)
assert eq(DS.wasmI32ToNumber(45n), 45)

assert eq(Conv.wasmI32ToNumber(0n), 0)
assert eq(DS.wasmI32ToNumber(0n), 0)

assert eq(Conv.wasmI32ToNumber(-1073741824n), -1073741824)
assert eq(DS.wasmI32ToNumber(-1073741824n), -1073741824)

assert eq(Conv.wasmI32ToNumber(1073741823n), 1073741823)
assert eq(DS.wasmI32ToNumber(1073741823n), 1073741823)

// heap allocated
assert eq(Conv.wasmI32ToNumber(-1073741825n), -1073741825)
assert eq(DS.wasmI32ToNumber(-1073741825n), -1073741825)

assert eq(Conv.wasmI32ToNumber(1073741824n), 1073741824)
assert eq(DS.wasmI32ToNumber(1073741824n), 1073741824)

assert eq(Conv.wasmI32ToNumber(-2147483648n), -2147483648)
assert eq(DS.wasmI32ToNumber(-2147483648n), -2147483648)

assert eq(Conv.wasmI32ToNumber(2147483647n), 2147483647)
assert eq(DS.wasmI32ToNumber(2147483647n), 2147483647)
}

test()
6 changes: 3 additions & 3 deletions compiler/test/runtime/unsafe/wasmi64.test.gr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module WasmI64Test

from "runtime/unsafe/wasmi64" include WasmI64
from "runtime/unsafe/conv" include Conv
from "runtime/unsafe/dataStructures" include DataStructures as DS

@unsafe
let test = () => {
Expand Down Expand Up @@ -88,8 +88,8 @@ let test = () => {
assert WasmI64.extendS32(0x80000000N) == 0xffffffff80000000N

// Grain conversion tests
assert eq(Conv.toInt64(45N), 45L)
assert Conv.fromInt64(45L) == 45N
assert eq(DS.Int64.toInt64(45N), 45L)
assert DS.Int64.fromInt64(45L) == 45N
}

test()
66 changes: 33 additions & 33 deletions compiler/test/runtime/unsafe/wasmref.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module WasmRefTest
from "runtime/unsafe/wasmref" include WasmRef
from "runtime/unsafe/wasmi32" include WasmI32
from "runtime/unsafe/wasmi64" include WasmI64
from "runtime/dataStructures" include DataStructures
from "runtime/unsafe/dataStructures" include DataStructures as DS

primitive (!) = "@not"
primitive (is) = "@is"
Expand Down Expand Up @@ -101,18 +101,18 @@ module WasmArrayRef {
primitive getCompoundValueArrayRef = "@compound_value.refarray"
@unsafe
let test = () => {
let arrRef = WasmRef.fromGrain([>])
let unsafeArrData = getCompoundValueArrayRef(arrRef)
let arrData = DataStructures.getCompoundValueArrayRef(arrRef)
let arr = [>]
let unsafeArrData = getCompoundValueArrayRef(WasmRef.fromGrain(arr))
let arrData = DS.Array.getData(DS.Array.fromGrain(arr))
assert WasmArrayRef.fromWasmRef(unsafeArrData) is arrData
}
test()
// WasmArrayRef.getI8S / WasmArrayRef.setI8
@unsafe
let test = () => {
let str = "Hello World"
let strRef = WasmRef.fromGrain(str)
let strData = DataStructures.getStringArrayRef(strRef)
let strRef = DS.String.fromGrain(str)
let strData = DS.String.getData(strRef)
use WasmI32.{ (==) }
assert WasmArrayRef.getI8S(strData, 0n) == 0x48n // 'H'
assert WasmArrayRef.getI8S(strData, 1n) == 0x65n // 'e'
Expand All @@ -125,8 +125,8 @@ module WasmArrayRef {
assert WasmArrayRef.getI8S(strData, 8n) == 0x72n // 'r'
assert WasmArrayRef.getI8S(strData, 9n) == 0x6Cn // 'l'
assert WasmArrayRef.getI8S(strData, 10n) == 0x64n // 'd'
let bytes = DataStructures.allocateBytes(1n)
let bytesData = DataStructures.getBytesArrayRef(bytes)
let bytes = DS.Bytes.make(1n)
let bytesData = DS.Bytes.getData(bytes)
assert WasmArrayRef.getI8S(bytesData, 0n) == 0n
WasmArrayRef.setI8(bytesData, 0n, 1n)
assert WasmArrayRef.getI8S(bytesData, 0n) == 1n
Expand All @@ -138,8 +138,8 @@ module WasmArrayRef {
@unsafe
let test = () => {
let str = "Hello World"
let strRef = WasmRef.fromGrain(str)
let strData = DataStructures.getStringArrayRef(strRef)
let strRef = DS.String.fromGrain(str)
let strData = DS.String.getData(strRef)
use WasmI32.{ (==) }
assert WasmArrayRef.getI8U(strData, 0n) == 0x48n // 'H'
assert WasmArrayRef.getI8U(strData, 1n) == 0x65n // 'e'
Expand All @@ -152,8 +152,8 @@ module WasmArrayRef {
assert WasmArrayRef.getI8U(strData, 8n) == 0x72n // 'r'
assert WasmArrayRef.getI8U(strData, 9n) == 0x6Cn // 'l'
assert WasmArrayRef.getI8U(strData, 10n) == 0x64n // 'd'
let bytes = DataStructures.allocateBytes(1n)
let bytesData = DataStructures.getBytesArrayRef(bytes)
let bytes = DS.Bytes.make(1n)
let bytesData = DS.Bytes.getData(bytes)
assert WasmArrayRef.getI8U(bytesData, 0n) == 0n
WasmArrayRef.setI8(bytesData, 0n, 1n)
assert WasmArrayRef.getI8U(bytesData, 0n) == 1n
Expand All @@ -166,7 +166,7 @@ module WasmArrayRef {
let test = () => {
let bigInt = 1t
let bigIntRef = WasmRef.fromGrain(bigInt)
let bigIntData = DataStructures.getBigIntArrayRef(bigIntRef)
let bigIntData = DS.BigInt.getLimbData(bigIntRef)
use WasmI64.{ (==) }
assert WasmArrayRef.getI64(bigIntData, 0n) == 1N
WasmArrayRef.setI64(bigIntData, 0n, -1N)
Expand All @@ -177,8 +177,8 @@ module WasmArrayRef {
@unsafe
let test = () => {
let arr = [> true, false]
let arrRef = WasmRef.fromGrain(arr)
let arrData = DataStructures.getCompoundValueArrayRef(arrRef)
let arrRef = DS.Array.fromGrain(arr)
let arrData = DS.Array.getData(arrRef)
assert WasmArrayRef.getAny(arrData, 0n) is WasmRef.fromGrain(true)
assert WasmArrayRef.getAny(arrData, 1n) is WasmRef.fromGrain(false)
WasmArrayRef.setAny(arrData, 0n, WasmRef.fromGrain(false))
Expand All @@ -191,8 +191,8 @@ module WasmArrayRef {
@unsafe
let test = () => {
use WasmI32.{ (==) }
let bytesRef = DataStructures.allocateBytes(4n)
let bytesData = DataStructures.getBytesArrayRef(bytesRef)
let bytesRef = DS.Bytes.make(4n)
let bytesData = DS.Bytes.getData(bytesRef)
assert WasmArrayRef.getI8S(bytesData, 0n) == 0n
assert WasmArrayRef.getI8S(bytesData, 1n) == 0n
assert WasmArrayRef.getI8S(bytesData, 2n) == 0n
Expand All @@ -213,11 +213,11 @@ module WasmArrayRef {
@unsafe
let test = () => {
use WasmI32.{ (==) }
let bytes1Ref = DataStructures.allocateBytes(4n)
let bytes1Data = DataStructures.getBytesArrayRef(bytes1Ref)
let bytes1Ref = DS.Bytes.make(4n)
let bytes1Data = DS.Bytes.getData(bytes1Ref)
WasmArrayRef.fillI8(bytes1Data, 0n, 3n, 4n)
let bytes2Ref = DataStructures.allocateBytes(4n)
let bytes2Data = DataStructures.getBytesArrayRef(bytes2Ref)
let bytes2Ref = DS.Bytes.make(4n)
let bytes2Data = DS.Bytes.getData(bytes2Ref)
assert WasmArrayRef.getI8S(bytes2Data, 0n) == 0n
assert WasmArrayRef.getI8S(bytes2Data, 1n) == 0n
assert WasmArrayRef.getI8S(bytes2Data, 2n) == 0n
Expand All @@ -233,14 +233,14 @@ module WasmArrayRef {
@unsafe
let test = () => {
use WasmI64.{ (==) }
let bigInt1Ref = DataStructures.allocateBigInt(4n)
let bigInt1Data = DataStructures.getBigIntArrayRef(bigInt1Ref)
let bigInt1Ref = DS.BigInt.make(4n)
let bigInt1Data = DS.BigInt.getLimbData(bigInt1Ref)
WasmArrayRef.setI64(bigInt1Data, 0n, 3N)
WasmArrayRef.setI64(bigInt1Data, 1n, 3N)
WasmArrayRef.setI64(bigInt1Data, 2n, 3N)
WasmArrayRef.setI64(bigInt1Data, 3n, 3N)
let bigInt2Ref = DataStructures.allocateBigInt(4n)
let bigInt2Data = DataStructures.getBigIntArrayRef(bigInt2Ref)
let bigInt2Ref = DS.BigInt.make(4n)
let bigInt2Data = DS.BigInt.getLimbData(bigInt2Ref)
assert WasmArrayRef.getI64(bigInt2Data, 0n) == 0N
assert WasmArrayRef.getI64(bigInt2Data, 1n) == 0N
assert WasmArrayRef.getI64(bigInt2Data, 2n) == 0N
Expand All @@ -257,10 +257,10 @@ module WasmArrayRef {
let test = () => {
let trueRef = WasmRef.fromGrain(true)
let falseRef = WasmRef.fromGrain(false)
let arr1Ref = DataStructures.allocateArray(4n, trueRef)
let arr1Data = DataStructures.getCompoundValueArrayRef(arr1Ref)
let arr2Ref = DataStructures.allocateArray(4n, falseRef)
let arr2Data = DataStructures.getCompoundValueArrayRef(arr2Ref)
let arr1Ref = DS.Array.make(4n, trueRef)
let arr1Data = DS.Array.getData(arr1Ref)
let arr2Ref = DS.Array.make(4n, falseRef)
let arr2Data = DS.Array.getData(arr2Ref)
assert WasmArrayRef.getAny(arr2Data, 0n) is falseRef
assert WasmArrayRef.getAny(arr2Data, 1n) is falseRef
assert WasmArrayRef.getAny(arr2Data, 2n) is falseRef
Expand All @@ -276,10 +276,10 @@ module WasmArrayRef {
@unsafe
let test = () => {
use WasmI32.{ (==), (<), (>) }
let str1Ref = WasmRef.fromGrain("ABC")
let str1Data = DataStructures.getStringArrayRef(str1Ref)
let str2Ref = WasmRef.fromGrain("CBA")
let str2Data = DataStructures.getStringArrayRef(str2Ref)
let str1Ref = DS.String.fromGrain("ABC")
let str1Data = DS.String.getData(str1Ref)
let str2Ref = DS.String.fromGrain("CBA")
let str2Data = DS.String.getData(str2Ref)
// No offset, full length comparisons
assert WasmArrayRef.compareI8(str1Data, 0n, str2Data, 0n, 3n) < 0n
assert WasmArrayRef.compareI8(str2Data, 0n, str1Data, 0n, 3n) > 0n
Expand Down
2 changes: 1 addition & 1 deletion docs/contributor/data_representations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

As of Grain `v0.8` [Wasm GC](https://github.com/WebAssembly/gc) is used to represent all grain values. This means that all values are represented either as an `ref i31` or `struct`. We use `ref i31`s to represent "stack" values, which are values that can be stored directly in a WebAssembly `i32`, and we use `struct`s to represent "heap" values, which are values that require more than 32 bits of data to represent. The layout of the `struct`s is described in the section on heap-allocated data.

While this document describes the structure of grain values directly it is preferable to use helper functions provided by the runtime through `runtime/unsafe/conv` and `runtime/dataStructures` when manipulating grain values.
While this document describes the structure of grain values directly it is preferable to use helper functions provided by the runtime through `runtime/unsafe/dataStructures` when manipulating grain values.

## Value tagging

Expand Down
2 changes: 1 addition & 1 deletion docs/contributor/low_level_programming.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Grain is overwhelmingly a high-level programming language, but it provides a few

Grain has five unsafe types, `WasmI32`, `WasmI64`, `WasmF32`, `WasmF64` and `WasmRef`. Unlike all other Grain types which are always represented as a `GrainValue`, these special types are represented by their corresponding WebAssembly types. This makes these types **incompatible** with regular Grain values, and they cannot be used with generic functions (like `print`) or appear in Grain's heap values (like in a `list`, `array`, `tuple` or any other high level dataStructure). While the typechecker will often prevent you from using them incorrectly, some uses may not be caught (#1153).

Libraries for working with these types can be found in `stdlib/runtime/unsafe` and map directly to WebAssembly instructions. `runtime/debugPrint` can be used to print values of these types for debugging purposes as they cannot be printed with the regular `print` function due to their incompatibility with regular Grain values.
Libraries for working with these types can be found in `stdlib/runtime/unsafe` and map directly to WebAssembly instructions. `runtime/unsafe/debugPrint` can be used to print values of these types for debugging purposes as they cannot be printed with the regular `print` function due to their incompatibility with regular Grain values.

## `@unsafe`

Expand Down
Loading
Loading