Repository: tetratelabs/wazero
Pull request #585 (2022-05-23 02:33:59)

wasi: returns fixed resolutin via ClockResGet
As pointed in https://github.com/tetratelabs/wazero/issues/526#issuecomment-1134034760, 
swift wasm binaries require clock_resg_get to return SUCCESS to run without unreachable.

For now, we temporarily fix the value `1000` to nanosec, and later we will do the overhaul on this
together with `ClockTimeGet` as these two implementations must be well aligned.


Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>

mathetake: cc @inkeliz this will allow you to pass tests with Swift 

Patch:
diff --git a/wasi/wasi.go b/wasi/wasi.go
index a6a8cd0f..d439fe4d 100644
--- a/wasi/wasi.go
+++ b/wasi/wasi.go
@@ -640,9 +640,31 @@ func (a *snapshotPreview1) EnvironSizesGet(ctx context.Context, m api.Module, re
 	return ErrnoSuccess
 }
 
-// ClockResGet is the WASI function named functionClockResGet and is stubbed for GrainLang per #271
+// ClockResGet is the WASI function named functionClockResGet that returns the resolution of time values returned by ClockTimeGet.
+//
+// * id - The clock id for which to return the time.
+// * resultResolution - the offset to write the resolution to m.Memory
+//   * the resolution is an uint64 little-endian encoding.
+//
+// For example, if the resolution is 100ns, this function writes the below to `m.Memory`:
+//
+//                                      uint64le
+//                    +-------------------------------------+
+//                    |                                     |
+//          []byte{?, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ?}
+//  resultResolution --^
+//
+// Note: importClockResGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
+// Note: This is similar to `clock_getres` in POSIX.
+// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
+// See https://linux.die.net/man/3/clock_getres
 func (a *snapshotPreview1) ClockResGet(ctx context.Context, m api.Module, id uint32, resultResolution uint32) Errno {
-	return ErrnoNosys // stubbed for GrainLang per #271
+	const resolution uint64 = 1000 // ns
+	// fixed for GrainLang per #271 and Swift per https://github.com/tetratelabs/wazero/issues/526#issuecomment-1134034760
+	if !m.Memory().WriteUint64Le(ctx, resultResolution, resolution) {
+		return ErrnoFault
+	}
+	return ErrnoSuccess
 }
 
 // ClockTimeGet is the WASI function named functionClockTimeGet that returns the time value of a clock (time.Now).


Test patch:
diff --git a/wasi/wasi_test.go b/wasi/wasi_test.go
index b319fc51..a43ddc84 100644
--- a/wasi/wasi_test.go
+++ b/wasi/wasi_test.go
@@ -415,15 +415,32 @@ func TestSnapshotPreview1_ClockResGet(t *testing.T) {
 	a, mod, fn := instantiateModule(testCtx, t, functionClockResGet, importClockResGet, nil)
 	defer mod.Close(testCtx)
 
+	resultResultion := uint32(1) // arbitrary offset
+	expectedMemory := []byte{
+		'?',                                     // resultResultion is after this
+		0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000).
+		'?', // stopped after encoding
+	}
 	t.Run("snapshotPreview1.ClockResGet", func(t *testing.T) {
-		require.Equal(t, ErrnoNosys, a.ClockResGet(testCtx, mod, 0, 0))
+		maskMemory(t, testCtx, mod, len(expectedMemory))
+		require.Equal(t, ErrnoSuccess, a.ClockResGet(testCtx, mod, 0, resultResultion))
+
+		actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
+		require.True(t, ok)
+		require.Equal(t, expectedMemory, actual)
 	})
 
 	t.Run(functionClockResGet, func(t *testing.T) {
-		results, err := fn.Call(testCtx, 0, 0)
+		maskMemory(t, testCtx, mod, len(expectedMemory))
+
+		results, err := fn.Call(testCtx, 0, uint64(resultResultion))
 		require.NoError(t, err)
 		errno := Errno(results[0]) // results[0] is the errno
-		require.Equal(t, ErrnoNosys, errno, ErrnoName(errno))
+		require.Equal(t, ErrnoSuccess, errno, ErrnoName(errno))
+
+		actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
+		require.True(t, ok)
+		require.Equal(t, expectedMemory, actual)
 	})
 }