summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/platform
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/platform')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/cpuid.go25
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.go59
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.s14
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_unsupported.go14
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/crypto.go17
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mmap_linux.go76
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mmap_other.go18
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unix.go49
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unsupported.go28
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mmap_windows.go97
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mremap_other.go23
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/mremap_unix.go21
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/path.go6
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/path_windows.go17
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/platform.go81
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/platform_amd64.go7
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/platform_arm64.go7
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/time.go76
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/time_cgo.go11
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/time_notcgo.go7
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/platform/time_windows.go40
21 files changed, 693 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid.go b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid.go
new file mode 100644
index 000000000..25d7d3fdc
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid.go
@@ -0,0 +1,25 @@
+package platform
+
+// CpuFeatureFlags exposes methods for querying CPU capabilities
+type CpuFeatureFlags interface {
+ // Has returns true when the specified flag (represented as uint64) is supported
+ Has(cpuFeature CpuFeature) bool
+ // HasExtra returns true when the specified extraFlag (represented as uint64) is supported
+ HasExtra(cpuFeature CpuFeature) bool
+}
+
+type CpuFeature uint64
+
+const (
+ // CpuFeatureAmd64SSE3 is the flag to query CpuFeatureFlags.Has for SSEv3 capabilities on amd64
+ CpuFeatureAmd64SSE3 CpuFeature = 1
+ // CpuFeatureAmd64SSE4_1 is the flag to query CpuFeatureFlags.Has for SSEv4.1 capabilities on amd64
+ CpuFeatureAmd64SSE4_1 CpuFeature = 1 << 19
+ // CpuFeatureAmd64SSE4_2 is the flag to query CpuFeatureFlags.Has for SSEv4.2 capabilities on amd64
+ CpuFeatureAmd64SSE4_2 CpuFeature = 1 << 20
+)
+
+const (
+ // CpuExtraFeatureAmd64ABM is the flag to query CpuFeatureFlags.HasExtra for Advanced Bit Manipulation capabilities (e.g. LZCNT) on amd64
+ CpuExtraFeatureAmd64ABM CpuFeature = 1 << 5
+)
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.go b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.go
new file mode 100644
index 000000000..8c9f1a9f3
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.go
@@ -0,0 +1,59 @@
+//go:build amd64 && !tinygo
+
+package platform
+
+// CpuFeatures exposes the capabilities for this CPU, queried via the Has, HasExtra methods
+var CpuFeatures CpuFeatureFlags = loadCpuFeatureFlags()
+
+// cpuFeatureFlags implements CpuFeatureFlags interface
+type cpuFeatureFlags struct {
+ flags uint64
+ extraFlags uint64
+}
+
+// cpuid exposes the CPUID instruction to the Go layer (https://www.amd.com/system/files/TechDocs/25481.pdf)
+// implemented in impl_amd64.s
+func cpuid(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32)
+
+// cpuidAsBitmap combines the result of invoking cpuid to uint64 bitmap
+func cpuidAsBitmap(arg1, arg2 uint32) uint64 {
+ _ /* eax */, _ /* ebx */, ecx, edx := cpuid(arg1, arg2)
+ return (uint64(edx) << 32) | uint64(ecx)
+}
+
+// loadStandardRange load flags from the standard range, panics otherwise
+func loadStandardRange(id uint32) uint64 {
+ // ensure that the id is in the valid range, returned by cpuid(0,0)
+ maxRange, _, _, _ := cpuid(0, 0)
+ if id > maxRange {
+ panic("cannot query standard CPU flags")
+ }
+ return cpuidAsBitmap(id, 0)
+}
+
+// loadStandardRange load flags from the extended range, panics otherwise
+func loadExtendedRange(id uint32) uint64 {
+ // ensure that the id is in the valid range, returned by cpuid(0x80000000,0)
+ maxRange, _, _, _ := cpuid(0x80000000, 0)
+ if id > maxRange {
+ panic("cannot query extended CPU flags")
+ }
+ return cpuidAsBitmap(id, 0)
+}
+
+func loadCpuFeatureFlags() CpuFeatureFlags {
+ return &cpuFeatureFlags{
+ flags: loadStandardRange(1),
+ extraFlags: loadExtendedRange(0x80000001),
+ }
+}
+
+// Has implements the same method on the CpuFeatureFlags interface
+func (f *cpuFeatureFlags) Has(cpuFeature CpuFeature) bool {
+ return (f.flags & uint64(cpuFeature)) != 0
+}
+
+// HasExtra implements the same method on the CpuFeatureFlags interface
+func (f *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool {
+ return (f.extraFlags & uint64(cpuFeature)) != 0
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.s b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.s
new file mode 100644
index 000000000..8d483f3a6
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.s
@@ -0,0 +1,14 @@
+#include "textflag.h"
+
+// lifted from github.com/intel-go/cpuid and src/internal/cpu/cpu_x86.s
+// func cpuid(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32)
+TEXT ·cpuid(SB), NOSPLIT, $0-24
+ MOVL arg1+0(FP), AX
+ MOVL arg2+4(FP), CX
+ CPUID
+ MOVL AX, eax+8(FP)
+ MOVL BX, ebx+12(FP)
+ MOVL CX, ecx+16(FP)
+ MOVL DX, edx+20(FP)
+ RET
+
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_unsupported.go
new file mode 100644
index 000000000..8ae826d36
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_unsupported.go
@@ -0,0 +1,14 @@
+//go:build !amd64 || tinygo
+
+package platform
+
+var CpuFeatures CpuFeatureFlags = &cpuFeatureFlags{}
+
+// cpuFeatureFlags implements CpuFeatureFlags for unsupported platforms
+type cpuFeatureFlags struct{}
+
+// Has implements the same method on the CpuFeatureFlags interface
+func (c *cpuFeatureFlags) Has(cpuFeature CpuFeature) bool { return false }
+
+// HasExtra implements the same method on the CpuFeatureFlags interface
+func (c *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool { return false }
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/crypto.go b/vendor/github.com/tetratelabs/wazero/internal/platform/crypto.go
new file mode 100644
index 000000000..c141f00f0
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/crypto.go
@@ -0,0 +1,17 @@
+package platform
+
+import (
+ "io"
+ "math/rand"
+)
+
+// seed is a fixed seed value for NewFakeRandSource.
+//
+// Trivia: While arbitrary, 42 was chosen as it is the "Ultimate Answer" in
+// the Douglas Adams novel "The Hitchhiker's Guide to the Galaxy."
+const seed = int64(42)
+
+// NewFakeRandSource returns a deterministic source of random values.
+func NewFakeRandSource() io.Reader {
+ return rand.New(rand.NewSource(seed))
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_linux.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_linux.go
new file mode 100644
index 000000000..55906e827
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_linux.go
@@ -0,0 +1,76 @@
+package platform
+
+import (
+ "math/bits"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "syscall"
+)
+
+const (
+ // https://man7.org/linux/man-pages/man2/mmap.2.html
+ __MAP_HUGE_SHIFT = 26
+ __MAP_HUGETLB = 0x40000
+)
+
+var hugePagesConfigs []hugePagesConfig
+
+type hugePagesConfig struct {
+ size int
+ flag int
+}
+
+func (hpc *hugePagesConfig) match(size int) bool {
+ return (size & (hpc.size - 1)) == 0
+}
+
+func init() {
+ dirents, err := os.ReadDir("/sys/kernel/mm/hugepages/")
+ if err != nil {
+ return
+ }
+
+ for _, dirent := range dirents {
+ name := dirent.Name()
+ if !strings.HasPrefix(name, "hugepages-") {
+ continue
+ }
+ if !strings.HasSuffix(name, "kB") {
+ continue
+ }
+ n, err := strconv.ParseUint(name[10:len(name)-2], 10, 64)
+ if err != nil {
+ continue
+ }
+ if bits.OnesCount64(n) != 1 {
+ continue
+ }
+ n *= 1024
+ hugePagesConfigs = append(hugePagesConfigs, hugePagesConfig{
+ size: int(n),
+ flag: int(bits.TrailingZeros64(n)<<__MAP_HUGE_SHIFT) | __MAP_HUGETLB,
+ })
+ }
+
+ sort.Slice(hugePagesConfigs, func(i, j int) bool {
+ return hugePagesConfigs[i].size > hugePagesConfigs[j].size
+ })
+}
+
+func mmapCodeSegment(size, prot int) ([]byte, error) {
+ flags := syscall.MAP_ANON | syscall.MAP_PRIVATE
+
+ for _, hugePagesConfig := range hugePagesConfigs {
+ if hugePagesConfig.match(size) {
+ b, err := syscall.Mmap(-1, 0, size, prot, flags|hugePagesConfig.flag)
+ if err != nil {
+ continue
+ }
+ return b, nil
+ }
+ }
+
+ return syscall.Mmap(-1, 0, size, prot, flags)
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_other.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_other.go
new file mode 100644
index 000000000..ed5c40a4d
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_other.go
@@ -0,0 +1,18 @@
+// Separated from linux which has support for huge pages.
+//go:build darwin || freebsd
+
+package platform
+
+import "syscall"
+
+func mmapCodeSegment(size, prot int) ([]byte, error) {
+ return syscall.Mmap(
+ -1,
+ 0,
+ size,
+ prot,
+ // Anonymous as this is not an actual file, but a memory,
+ // Private as this is in-process memory region.
+ syscall.MAP_ANON|syscall.MAP_PRIVATE,
+ )
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unix.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unix.go
new file mode 100644
index 000000000..a61996d58
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unix.go
@@ -0,0 +1,49 @@
+//go:build (darwin || linux || freebsd) && !tinygo
+
+package platform
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+const (
+ mmapProtAMD64 = syscall.PROT_READ | syscall.PROT_WRITE | syscall.PROT_EXEC
+ mmapProtARM64 = syscall.PROT_READ | syscall.PROT_WRITE
+)
+
+const MmapSupported = true
+
+func munmapCodeSegment(code []byte) error {
+ return syscall.Munmap(code)
+}
+
+// mmapCodeSegmentAMD64 gives all read-write-exec permission to the mmap region
+// to enter the function. Otherwise, segmentation fault exception is raised.
+func mmapCodeSegmentAMD64(size int) ([]byte, error) {
+ // The region must be RWX: RW for writing native codes, X for executing the region.
+ return mmapCodeSegment(size, mmapProtAMD64)
+}
+
+// mmapCodeSegmentARM64 cannot give all read-write-exec permission to the mmap region.
+// Otherwise, the mmap systemcall would raise an error. Here we give read-write
+// to the region so that we can write contents at call-sites. Callers are responsible to
+// execute MprotectRX on the returned buffer.
+func mmapCodeSegmentARM64(size int) ([]byte, error) {
+ // The region must be RW: RW for writing native codes.
+ return mmapCodeSegment(size, mmapProtARM64)
+}
+
+// MprotectRX is like syscall.Mprotect with RX permission, defined locally so that freebsd compiles.
+func MprotectRX(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ }
+ const prot = syscall.PROT_READ | syscall.PROT_EXEC
+ _, _, e1 := syscall.Syscall(syscall.SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = syscall.Errno(e1)
+ }
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unsupported.go
new file mode 100644
index 000000000..27833db37
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_unsupported.go
@@ -0,0 +1,28 @@
+//go:build !(darwin || linux || freebsd || windows) || tinygo
+
+package platform
+
+import (
+ "fmt"
+ "runtime"
+)
+
+var errUnsupported = fmt.Errorf("mmap unsupported on GOOS=%s. Use interpreter instead.", runtime.GOOS)
+
+const MmapSupported = false
+
+func munmapCodeSegment(code []byte) error {
+ panic(errUnsupported)
+}
+
+func mmapCodeSegmentAMD64(size int) ([]byte, error) {
+ panic(errUnsupported)
+}
+
+func mmapCodeSegmentARM64(size int) ([]byte, error) {
+ panic(errUnsupported)
+}
+
+func MprotectRX(b []byte) (err error) {
+ panic(errUnsupported)
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_windows.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_windows.go
new file mode 100644
index 000000000..69fcb6d6b
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mmap_windows.go
@@ -0,0 +1,97 @@
+package platform
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procVirtualAlloc = kernel32.NewProc("VirtualAlloc")
+ procVirtualProtect = kernel32.NewProc("VirtualProtect")
+ procVirtualFree = kernel32.NewProc("VirtualFree")
+)
+
+const (
+ windows_MEM_COMMIT uintptr = 0x00001000
+ windows_MEM_RELEASE uintptr = 0x00008000
+ windows_PAGE_READWRITE uintptr = 0x00000004
+ windows_PAGE_EXECUTE_READ uintptr = 0x00000020
+ windows_PAGE_EXECUTE_READWRITE uintptr = 0x00000040
+)
+
+const MmapSupported = true
+
+func munmapCodeSegment(code []byte) error {
+ return freeMemory(code)
+}
+
+// allocateMemory commits the memory region via the "VirtualAlloc" function.
+// See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
+func allocateMemory(size uintptr, protect uintptr) (uintptr, error) {
+ address := uintptr(0) // system determines where to allocate the region.
+ alloctype := windows_MEM_COMMIT
+ if r, _, err := procVirtualAlloc.Call(address, size, alloctype, protect); r == 0 {
+ return 0, fmt.Errorf("compiler: VirtualAlloc error: %w", ensureErr(err))
+ } else {
+ return r, nil
+ }
+}
+
+// freeMemory releases the memory region via the "VirtualFree" function.
+// See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree
+func freeMemory(code []byte) error {
+ address := unsafe.Pointer(&code[0])
+ size := uintptr(0) // size must be 0 because we're using MEM_RELEASE.
+ freetype := windows_MEM_RELEASE
+ if r, _, err := procVirtualFree.Call(uintptr(address), size, freetype); r == 0 {
+ return fmt.Errorf("compiler: VirtualFree error: %w", ensureErr(err))
+ }
+ return nil
+}
+
+func virtualProtect(address, size, newprotect uintptr, oldprotect *uint32) error {
+ if r, _, err := procVirtualProtect.Call(address, size, newprotect, uintptr(unsafe.Pointer(oldprotect))); r == 0 {
+ return fmt.Errorf("compiler: VirtualProtect error: %w", ensureErr(err))
+ }
+ return nil
+}
+
+func mmapCodeSegmentAMD64(size int) ([]byte, error) {
+ p, err := allocateMemory(uintptr(size), windows_PAGE_EXECUTE_READWRITE)
+ if err != nil {
+ return nil, err
+ }
+
+ return unsafe.Slice((*byte)(unsafe.Pointer(p)), size), nil
+}
+
+func mmapCodeSegmentARM64(size int) ([]byte, error) {
+ p, err := allocateMemory(uintptr(size), windows_PAGE_READWRITE)
+ if err != nil {
+ return nil, err
+ }
+
+ return unsafe.Slice((*byte)(unsafe.Pointer(p)), size), nil
+}
+
+var old = uint32(windows_PAGE_READWRITE)
+
+func MprotectRX(b []byte) (err error) {
+ err = virtualProtect(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), windows_PAGE_EXECUTE_READ, &old)
+ return
+}
+
+// ensureErr returns syscall.EINVAL when the input error is nil.
+//
+// We are supposed to use "GetLastError" which is more precise, but it is not safe to execute in goroutines. While
+// "GetLastError" is thread-local, goroutines are not pinned to threads.
+//
+// See https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
+func ensureErr(err error) error {
+ if err != nil {
+ return err
+ }
+ return syscall.EINVAL
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mremap_other.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mremap_other.go
new file mode 100644
index 000000000..5cba99fb2
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mremap_other.go
@@ -0,0 +1,23 @@
+//go:build !(darwin || linux || freebsd) || tinygo
+
+package platform
+
+func remapCodeSegmentAMD64(code []byte, size int) ([]byte, error) {
+ b, err := mmapCodeSegmentAMD64(size)
+ if err != nil {
+ return nil, err
+ }
+ copy(b, code)
+ mustMunmapCodeSegment(code)
+ return b, nil
+}
+
+func remapCodeSegmentARM64(code []byte, size int) ([]byte, error) {
+ b, err := mmapCodeSegmentARM64(size)
+ if err != nil {
+ return nil, err
+ }
+ copy(b, code)
+ mustMunmapCodeSegment(code)
+ return b, nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/mremap_unix.go b/vendor/github.com/tetratelabs/wazero/internal/platform/mremap_unix.go
new file mode 100644
index 000000000..8f42d44fd
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/mremap_unix.go
@@ -0,0 +1,21 @@
+//go:build (darwin || linux || freebsd) && !tinygo
+
+package platform
+
+func remapCodeSegmentAMD64(code []byte, size int) ([]byte, error) {
+ return remapCodeSegment(code, size, mmapProtAMD64)
+}
+
+func remapCodeSegmentARM64(code []byte, size int) ([]byte, error) {
+ return remapCodeSegment(code, size, mmapProtARM64)
+}
+
+func remapCodeSegment(code []byte, size, prot int) ([]byte, error) {
+ b, err := mmapCodeSegment(size, prot)
+ if err != nil {
+ return nil, err
+ }
+ copy(b, code)
+ mustMunmapCodeSegment(code)
+ return b, nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/path.go b/vendor/github.com/tetratelabs/wazero/internal/platform/path.go
new file mode 100644
index 000000000..361049ae2
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/path.go
@@ -0,0 +1,6 @@
+//go:build !windows
+
+package platform
+
+// ToPosixPath returns the input, as only windows might return backslashes.
+func ToPosixPath(in string) string { return in }
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/path_windows.go b/vendor/github.com/tetratelabs/wazero/internal/platform/path_windows.go
new file mode 100644
index 000000000..77c4187d9
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/path_windows.go
@@ -0,0 +1,17 @@
+package platform
+
+import "strings"
+
+// ToPosixPath returns the input, converting any backslashes to forward ones.
+func ToPosixPath(in string) string {
+ // strings.Map only allocates on change, which is good enough especially as
+ // path.Join uses forward slash even on windows.
+ return strings.Map(windowsToPosixSeparator, in)
+}
+
+func windowsToPosixSeparator(r rune) rune {
+ if r == '\\' {
+ return '/'
+ }
+ return r
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/platform.go b/vendor/github.com/tetratelabs/wazero/internal/platform/platform.go
new file mode 100644
index 000000000..c6dc0f857
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/platform.go
@@ -0,0 +1,81 @@
+// Package platform includes runtime-specific code needed for the compiler or otherwise.
+//
+// Note: This is a dependency-free alternative to depending on parts of Go's x/sys.
+// See /RATIONALE.md for more context.
+package platform
+
+import (
+ "runtime"
+)
+
+// archRequirementsVerified is set by platform-specific init to true if the platform is supported
+var archRequirementsVerified bool
+
+// CompilerSupported is exported for tests and includes constraints here and also the assembler.
+func CompilerSupported() bool {
+ switch runtime.GOOS {
+ case "darwin", "windows", "linux", "freebsd":
+ default:
+ return false
+ }
+
+ return archRequirementsVerified
+}
+
+// MmapCodeSegment copies the code into the executable region and returns the byte slice of the region.
+//
+// See https://man7.org/linux/man-pages/man2/mmap.2.html for mmap API and flags.
+func MmapCodeSegment(size int) ([]byte, error) {
+ if size == 0 {
+ panic("BUG: MmapCodeSegment with zero length")
+ }
+ if runtime.GOARCH == "amd64" {
+ return mmapCodeSegmentAMD64(size)
+ } else {
+ return mmapCodeSegmentARM64(size)
+ }
+}
+
+// RemapCodeSegment reallocates the memory mapping of an existing code segment
+// to increase its size. The previous code mapping is unmapped and must not be
+// reused after the function returns.
+//
+// This is similar to mremap(2) on linux, and emulated on platforms which do not
+// have this syscall.
+//
+// See https://man7.org/linux/man-pages/man2/mremap.2.html
+func RemapCodeSegment(code []byte, size int) ([]byte, error) {
+ if size < len(code) {
+ panic("BUG: RemapCodeSegment with size less than code")
+ }
+ if code == nil {
+ return MmapCodeSegment(size)
+ }
+ if runtime.GOARCH == "amd64" {
+ return remapCodeSegmentAMD64(code, size)
+ } else {
+ return remapCodeSegmentARM64(code, size)
+ }
+}
+
+// MunmapCodeSegment unmaps the given memory region.
+func MunmapCodeSegment(code []byte) error {
+ if len(code) == 0 {
+ panic("BUG: MunmapCodeSegment with zero length")
+ }
+ return munmapCodeSegment(code)
+}
+
+// mustMunmapCodeSegment panics instead of returning an error to the
+// application.
+//
+// # Why panic?
+//
+// It is less disruptive to the application to leak the previous block if it
+// could be unmapped than to leak the new block and return an error.
+// Realistically, either scenarios are pretty hard to debug, so we panic.
+func mustMunmapCodeSegment(code []byte) {
+ if err := munmapCodeSegment(code); err != nil {
+ panic(err)
+ }
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/platform_amd64.go b/vendor/github.com/tetratelabs/wazero/internal/platform/platform_amd64.go
new file mode 100644
index 000000000..59aaf5eae
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/platform_amd64.go
@@ -0,0 +1,7 @@
+package platform
+
+// init verifies that the current CPU supports the required AMD64 instructions
+func init() {
+ // Ensure SSE4.1 is supported.
+ archRequirementsVerified = CpuFeatures.Has(CpuFeatureAmd64SSE4_1)
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/platform_arm64.go b/vendor/github.com/tetratelabs/wazero/internal/platform/platform_arm64.go
new file mode 100644
index 000000000..caac58a3d
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/platform_arm64.go
@@ -0,0 +1,7 @@
+package platform
+
+// init verifies that the current CPU supports the required ARM64 features
+func init() {
+ // No further checks currently needed.
+ archRequirementsVerified = true
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/time.go b/vendor/github.com/tetratelabs/wazero/internal/platform/time.go
new file mode 100644
index 000000000..fa9da1acb
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/time.go
@@ -0,0 +1,76 @@
+package platform
+
+import (
+ "sync/atomic"
+ "time"
+
+ "github.com/tetratelabs/wazero/sys"
+)
+
+const (
+ ms = int64(time.Millisecond)
+ // FakeEpochNanos is midnight UTC 2022-01-01 and exposed for testing
+ FakeEpochNanos = 1640995200000 * ms
+)
+
+// NewFakeWalltime implements sys.Walltime with FakeEpochNanos that increases by 1ms each reading.
+// See /RATIONALE.md
+func NewFakeWalltime() sys.Walltime {
+ // AddInt64 returns the new value. Adjust so the first reading will be FakeEpochNanos
+ t := FakeEpochNanos - ms
+ return func() (sec int64, nsec int32) {
+ wt := atomic.AddInt64(&t, ms)
+ return wt / 1e9, int32(wt % 1e9)
+ }
+}
+
+// NewFakeNanotime implements sys.Nanotime that increases by 1ms each reading.
+// See /RATIONALE.md
+func NewFakeNanotime() sys.Nanotime {
+ // AddInt64 returns the new value. Adjust so the first reading will be zero.
+ t := int64(0) - ms
+ return func() int64 {
+ return atomic.AddInt64(&t, ms)
+ }
+}
+
+// FakeNanosleep implements sys.Nanosleep by returning without sleeping.
+var FakeNanosleep = sys.Nanosleep(func(int64) {})
+
+// FakeOsyield implements sys.Osyield by returning without yielding.
+var FakeOsyield = sys.Osyield(func() {})
+
+// Walltime implements sys.Walltime with time.Now.
+//
+// Note: This is only notably less efficient than it could be is reading
+// runtime.walltime(). time.Now defensively reads nanotime also, just in case
+// time.Since is used. This doubles the performance impact. However, wall time
+// is likely to be read less frequently than Nanotime. Also, doubling the cost
+// matters less on fast platforms that can return both in <=100ns.
+func Walltime() (sec int64, nsec int32) {
+ t := time.Now()
+ return t.Unix(), int32(t.Nanosecond())
+}
+
+// nanoBase uses time.Now to ensure a monotonic clock reading on all platforms
+// via time.Since.
+var nanoBase = time.Now()
+
+// nanotimePortable implements sys.Nanotime with time.Since.
+//
+// Note: This is less efficient than it could be is reading runtime.nanotime(),
+// Just to do that requires CGO.
+func nanotimePortable() int64 {
+ return time.Since(nanoBase).Nanoseconds()
+}
+
+// Nanotime implements sys.Nanotime with runtime.nanotime() if CGO is available
+// and time.Since if not.
+func Nanotime() int64 {
+ return nanotime()
+}
+
+// Nanosleep implements sys.Nanosleep with time.Sleep.
+func Nanosleep(ns int64) {
+ time.Sleep(time.Duration(ns))
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/time_cgo.go b/vendor/github.com/tetratelabs/wazero/internal/platform/time_cgo.go
new file mode 100644
index 000000000..ff01d90ce
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/time_cgo.go
@@ -0,0 +1,11 @@
+//go:build cgo && !windows
+
+package platform
+
+import _ "unsafe" // for go:linkname
+
+// nanotime uses runtime.nanotime as it is available on all platforms and
+// benchmarks faster than using time.Since.
+//
+//go:linkname nanotime runtime.nanotime
+func nanotime() int64
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/time_notcgo.go b/vendor/github.com/tetratelabs/wazero/internal/platform/time_notcgo.go
new file mode 100644
index 000000000..0697b7c70
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/time_notcgo.go
@@ -0,0 +1,7 @@
+//go:build !cgo && !windows
+
+package platform
+
+func nanotime() int64 {
+ return nanotimePortable()
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/time_windows.go b/vendor/github.com/tetratelabs/wazero/internal/platform/time_windows.go
new file mode 100644
index 000000000..58731fc8e
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/platform/time_windows.go
@@ -0,0 +1,40 @@
+//go:build windows
+
+package platform
+
+import (
+ "math/bits"
+ "time"
+ "unsafe"
+)
+
+var (
+ _QueryPerformanceCounter = kernel32.NewProc("QueryPerformanceCounter")
+ _QueryPerformanceFrequency = kernel32.NewProc("QueryPerformanceFrequency")
+)
+
+var qpcfreq uint64
+
+func init() {
+ _, _, _ = _QueryPerformanceFrequency.Call(uintptr(unsafe.Pointer(&qpcfreq)))
+}
+
+// On Windows, time.Time handled in time package cannot have the nanosecond precision.
+// The reason is that by default, it doesn't use QueryPerformanceCounter[1], but instead, use "interrupt time"
+// which doesn't support nanoseconds precision (though it is a monotonic) [2, 3, 4, 5].
+//
+// [1] https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter
+// [2] https://github.com/golang/go/blob/0cd309e12818f988693bf8e4d9f1453331dcf9f2/src/runtime/sys_windows_amd64.s#L297-L298
+// [3] https://github.com/golang/go/blob/0cd309e12818f988693bf8e4d9f1453331dcf9f2/src/runtime/os_windows.go#L549-L551
+// [4] https://github.com/golang/go/blob/master/src/runtime/time_windows.h#L7-L13
+// [5] http://web.archive.org/web/20210411000829/https://wrkhpi.wordpress.com/2007/08/09/getting-os-information-the-kuser_shared_data-structure/
+//
+// Therefore, on Windows, we directly invoke the syscall for QPC instead of time.Now or runtime.nanotime.
+// See https://github.com/golang/go/issues/31160 for example.
+func nanotime() int64 {
+ var counter uint64
+ _, _, _ = _QueryPerformanceCounter.Call(uintptr(unsafe.Pointer(&counter)))
+ hi, lo := bits.Mul64(counter, uint64(time.Second))
+ nanos, _ := bits.Div64(hi, lo, qpcfreq)
+ return int64(nanos)
+}