github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/platform/platform.go (about)

     1  // Package platform includes runtime-specific code needed for the compiler or otherwise.
     2  //
     3  // Note: This is a dependency-free alternative to depending on parts of Go's x/sys.
     4  // See /RATIONALE.md for more context.
     5  package platform
     6  
     7  import (
     8  	"regexp"
     9  	"runtime"
    10  )
    11  
    12  // IsAtLeastGo120 checks features added in 1.20. We can remove this when Go
    13  // 1.22 is out.
    14  var IsAtLeastGo120 = isAtLeastGo120(runtime.Version())
    15  
    16  func isAtLeastGo120(version string) bool {
    17  	return regexp.MustCompile("go1.[2-9][0-9][^0-9]").MatchString(version)
    18  }
    19  
    20  // archRequirementsVerified is set by platform-specific init to true if the platform is supported
    21  var archRequirementsVerified bool
    22  
    23  // CompilerSupported is exported for tests and includes constraints here and also the assembler.
    24  func CompilerSupported() bool {
    25  	switch runtime.GOOS {
    26  	case "darwin", "windows", "linux", "freebsd":
    27  	default:
    28  		return false
    29  	}
    30  
    31  	return archRequirementsVerified
    32  }
    33  
    34  // MmapCodeSegment copies the code into the executable region and returns the byte slice of the region.
    35  //
    36  // See https://man7.org/linux/man-pages/man2/mmap.2.html for mmap API and flags.
    37  func MmapCodeSegment(size int) ([]byte, error) {
    38  	if size == 0 {
    39  		panic("BUG: MmapCodeSegment with zero length")
    40  	}
    41  	if runtime.GOARCH == "amd64" {
    42  		return mmapCodeSegmentAMD64(size)
    43  	} else {
    44  		return mmapCodeSegmentARM64(size)
    45  	}
    46  }
    47  
    48  // RemapCodeSegment reallocates the memory mapping of an existing code segment
    49  // to increase its size. The previous code mapping is unmapped and must not be
    50  // reused after the function returns.
    51  //
    52  // This is similar to mremap(2) on linux, and emulated on platforms which do not
    53  // have this syscall.
    54  //
    55  // See https://man7.org/linux/man-pages/man2/mremap.2.html
    56  func RemapCodeSegment(code []byte, size int) ([]byte, error) {
    57  	if size < len(code) {
    58  		panic("BUG: RemapCodeSegment with size less than code")
    59  	}
    60  	if code == nil {
    61  		return MmapCodeSegment(size)
    62  	}
    63  	if runtime.GOARCH == "amd64" {
    64  		return remapCodeSegmentAMD64(code, size)
    65  	} else {
    66  		return remapCodeSegmentARM64(code, size)
    67  	}
    68  }
    69  
    70  // MunmapCodeSegment unmaps the given memory region.
    71  func MunmapCodeSegment(code []byte) error {
    72  	if len(code) == 0 {
    73  		panic("BUG: MunmapCodeSegment with zero length")
    74  	}
    75  	return munmapCodeSegment(code)
    76  }
    77  
    78  // mustMunmapCodeSegment panics instead of returning an error to the
    79  // application.
    80  //
    81  // # Why panic?
    82  //
    83  // It is less disruptive to the application to leak the previous block if it
    84  // could be unmapped than to leak the new block and return an error.
    85  // Realistically, either scenarios are pretty hard to debug, so we panic.
    86  func mustMunmapCodeSegment(code []byte) {
    87  	if err := munmapCodeSegment(code); err != nil {
    88  		panic(err)
    89  	}
    90  }