pull in ncruces/go-sqlite3 v0.20.3 with tetratelabs/wazero v1.8.2 (#3574)

This commit is contained in:
kim
2024-11-26 16:25:48 +00:00
committed by GitHub
parent 6a8af42647
commit 61f8f1e0e3
41 changed files with 374 additions and 226 deletions

View File

@ -96,14 +96,21 @@ systems are ones we test, but that doesn't necessarily mean other operating
system versions won't work.
We currently test Linux (Ubuntu and scratch), MacOS and Windows as packaged by
[GitHub Actions][11], as well compilation of 32-bit Linux and 64-bit FreeBSD.
[GitHub Actions][11], as well as nested VMs running on Linux for FreeBSD, NetBSD,
OpenBSD, DragonFly BSD, illumos and Solaris.
We also test cross compilation for many `GOOS` and `GOARCH` combinations.
* Interpreter
* Linux is tested on amd64 (native) as well arm64 and riscv64 via emulation.
* MacOS and Windows are only tested on amd64.
* Windows, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, illumos and Solaris are
tested only on amd64.
* macOS is tested only on arm64.
* Compiler
* Linux is tested on amd64 (native) as well arm64 via emulation.
* MacOS and Windows are only tested on amd64.
* Windows, FreeBSD, NetBSD, DragonFly BSD, illumos and Solaris are
tested only on amd64.
* macOS is tested only on arm64.
wazero has no dependencies and doesn't require CGO. This means it can also be
embedded in an application that doesn't use an operating system. This is a main

View File

@ -5,10 +5,15 @@
//
// Meanwhile, users who know their runtime.GOOS can operate with the compiler
// may choose to use NewRuntimeConfigCompiler explicitly.
//go:build (amd64 || arm64) && (darwin || linux || freebsd || windows)
//go:build (amd64 || arm64) && (linux || darwin || freebsd || netbsd || dragonfly || solaris || windows)
package wazero
import "github.com/tetratelabs/wazero/internal/platform"
func newRuntimeConfig() RuntimeConfig {
return NewRuntimeConfigCompiler()
if platform.CompilerSupported() {
return NewRuntimeConfigCompiler()
}
return NewRuntimeConfigInterpreter()
}

View File

@ -1,5 +1,5 @@
// This is the opposite constraint of config_supported.go
//go:build !(amd64 || arm64) || !(darwin || linux || freebsd || windows)
//go:build !(amd64 || arm64) || !(linux || darwin || freebsd || netbsd || dragonfly || solaris || windows)
package wazero

View File

@ -43,7 +43,7 @@ type LinearMemory interface {
}
// WithMemoryAllocator registers the given MemoryAllocator into the given
// context.Context.
// context.Context. The context must be passed when initializing a module.
func WithMemoryAllocator(ctx context.Context, allocator MemoryAllocator) context.Context {
if allocator != nil {
return context.WithValue(ctx, expctxkeys.MemoryAllocatorKey{}, allocator)

View File

@ -2196,7 +2196,7 @@ func (m *machine) Encode(ctx context.Context) (err error) {
}
// ResolveRelocations implements backend.Machine.
func (m *machine) ResolveRelocations(refToBinaryOffset []int, binary []byte, relocations []backend.RelocationInfo, _ []int) {
func (m *machine) ResolveRelocations(refToBinaryOffset []int, _ int, binary []byte, relocations []backend.RelocationInfo, _ []int) {
for _, r := range relocations {
offset := r.Offset
calleeFnOffset := refToBinaryOffset[r.FuncRef]

View File

@ -21,7 +21,7 @@ const (
// trampolineIslandInterval is the range of the trampoline island.
// Half of the range is used for the trampoline island, and the other half is used for the function.
trampolineIslandInterval = maxUnconditionalBranchOffset / 2
trampolineIslandInterval = (maxUnconditionalBranchOffset - 1) / 2
// maxNumFunctions explicitly specifies the maximum number of functions that can be allowed in a single executable.
maxNumFunctions = trampolineIslandInterval >> 6
@ -42,12 +42,13 @@ func (m *machine) CallTrampolineIslandInfo(numFunctions int) (interval, size int
// ResolveRelocations implements backend.Machine ResolveRelocations.
func (m *machine) ResolveRelocations(
refToBinaryOffset []int,
importedFns int,
executable []byte,
relocations []backend.RelocationInfo,
callTrampolineIslandOffsets []int,
) {
for _, islandOffset := range callTrampolineIslandOffsets {
encodeCallTrampolineIsland(refToBinaryOffset, islandOffset, executable)
encodeCallTrampolineIsland(refToBinaryOffset, importedFns, islandOffset, executable)
}
for _, r := range relocations {
@ -71,11 +72,15 @@ func (m *machine) ResolveRelocations(
// encodeCallTrampolineIsland encodes a trampoline island for the given functions.
// Each island consists of a trampoline instruction sequence for each function.
// Each trampoline instruction sequence consists of 4 instructions + 32-bit immediate.
func encodeCallTrampolineIsland(refToBinaryOffset []int, islandOffset int, executable []byte) {
for i := 0; i < len(refToBinaryOffset); i++ {
func encodeCallTrampolineIsland(refToBinaryOffset []int, importedFns int, islandOffset int, executable []byte) {
// We skip the imported functions: they don't need trampolines
// and are not accounted for.
binaryOffsets := refToBinaryOffset[importedFns:]
for i := 0; i < len(binaryOffsets); i++ {
trampolineOffset := islandOffset + trampolineCallSize*i
fnOffset := refToBinaryOffset[i]
fnOffset := binaryOffsets[i]
diff := fnOffset - (trampolineOffset + 16)
if diff > math.MaxInt32 || diff < math.MinInt32 {
// This case even amd64 can't handle. 4GB is too big.

View File

@ -77,11 +77,13 @@ type (
// ResolveRelocations resolves the relocations after emitting machine code.
// * refToBinaryOffset: the map from the function reference (ssa.FuncRef) to the executable offset.
// * importedFns: the max index of the imported functions at the beginning of refToBinaryOffset
// * executable: the binary to resolve the relocations.
// * relocations: the relocations to resolve.
// * callTrampolineIslandOffsets: the offsets of the trampoline islands in the executable.
ResolveRelocations(
refToBinaryOffset []int,
importedFns int,
executable []byte,
relocations []RelocationInfo,
callTrampolineIslandOffsets []int,

View File

@ -314,7 +314,7 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
// Resolve relocations for local function calls.
if len(rels) > 0 {
machine.ResolveRelocations(refToBinaryOffset, executable, rels, callTrampolineIslandOffsets)
machine.ResolveRelocations(refToBinaryOffset, importedFns, executable, rels, callTrampolineIslandOffsets)
}
if runtime.GOARCH == "arm64" {

View File

@ -28,3 +28,8 @@ const (
CpuExtraFeatureAmd64ABM CpuFeature = 1 << 5
// Note: when adding new features, ensure that the feature is included in CpuFeatureFlags.Raw.
)
const (
// CpuFeatureArm64Atomic is the flag to query CpuFeatureFlags.Has for Large System Extensions capabilities on arm64
CpuFeatureArm64Atomic CpuFeature = 1 << 21
)

View File

@ -1,4 +1,4 @@
//go:build amd64 && !tinygo
//go:build gc
package platform
@ -12,7 +12,7 @@ type cpuFeatureFlags struct {
}
// cpuid exposes the CPUID instruction to the Go layer (https://www.amd.com/system/files/TechDocs/25481.pdf)
// implemented in impl_amd64.s
// implemented in cpuid_amd64.s
func cpuid(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32)
// cpuidAsBitmap combines the result of invoking cpuid to uint64 bitmap.
@ -60,8 +60,9 @@ func (f *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool {
// Raw implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Raw() uint64 {
// Below, we only set the first 4 bits for the features we care about,
// instead of setting all the unnecessary bits obtained from the CPUID instruction.
// Below, we only set bits for the features we care about,
// instead of setting all the unnecessary bits obtained from the
// CPUID instruction.
var ret uint64
if f.Has(CpuFeatureAmd64SSE3) {
ret = 1 << 0

View File

@ -1,6 +1,9 @@
//go:build gc
#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
@ -11,4 +14,3 @@ TEXT ·cpuid(SB), NOSPLIT, $0-24
MOVL CX, ecx+16(FP)
MOVL DX, edx+20(FP)
RET

View File

@ -0,0 +1,71 @@
//go:build gc
package platform
import "runtime"
// CpuFeatures exposes the capabilities for this CPU, queried via the Has, HasExtra methods.
var CpuFeatures = loadCpuFeatureFlags()
// cpuFeatureFlags implements CpuFeatureFlags interface.
type cpuFeatureFlags struct {
isar0 uint64
isar1 uint64
}
// implemented in cpuid_arm64.s
func getisar0() uint64
// implemented in cpuid_arm64.s
func getisar1() uint64
func loadCpuFeatureFlags() CpuFeatureFlags {
switch runtime.GOOS {
case "darwin", "windows":
// These OSes do not allow userland to read the instruction set attribute registers,
// but basically require atomic instructions:
// - "darwin" is the desktop version (mobile version is "ios"),
// and the M1 is a ARMv8.4.
// - "windows" requires them from Windows 11, see page 12
// https://download.microsoft.com/download/7/8/8/788bf5ab-0751-4928-a22c-dffdc23c27f2/Minimum%20Hardware%20Requirements%20for%20Windows%2011.pdf
return &cpuFeatureFlags{
isar0: uint64(CpuFeatureArm64Atomic),
isar1: 0,
}
case "linux", "freebsd":
// These OSes allow userland to read the instruction set attribute registers,
// which is otherwise restricted to EL0:
// https://kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
// See these for contents of the registers:
// https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0
// https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers/ID-AA64ISAR1-EL1--AArch64-Instruction-Set-Attribute-Register-1
return &cpuFeatureFlags{
isar0: getisar0(),
isar1: getisar1(),
}
default:
return &cpuFeatureFlags{}
}
}
// Has implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Has(cpuFeature CpuFeature) bool {
return (f.isar0 & uint64(cpuFeature)) != 0
}
// HasExtra implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool {
return (f.isar1 & uint64(cpuFeature)) != 0
}
// Raw implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Raw() uint64 {
// Below, we only set bits for the features we care about,
// instead of setting all the unnecessary bits obtained from the
// instruction set attribute registers.
var ret uint64
if f.Has(CpuFeatureArm64Atomic) {
ret = 1 << 0
}
return ret
}

View File

@ -0,0 +1,21 @@
//go:build gc
#include "textflag.h"
// lifted from github.com/golang/sys and cpu/cpu_arm64.s
// func getisar0() uint64
TEXT ·getisar0(SB), NOSPLIT, $0-8
// get Instruction Set Attributes 0 into x0
// mrs x0, ID_AA64ISAR0_EL1 = d5380600
WORD $0xd5380600
MOVD R0, ret+0(FP)
RET
// func getisar1() uint64
TEXT ·getisar1(SB), NOSPLIT, $0-8
// get Instruction Set Attributes 1 into x0
// mrs x0, ID_AA64ISAR1_EL1 = d5380620
WORD $0xd5380620
MOVD R0, ret+0(FP)
RET

View File

@ -1,4 +1,4 @@
//go:build !amd64 || tinygo
//go:build !(amd64 || arm64) || !gc
package platform

View File

@ -1,5 +1,5 @@
// Separated from linux which has support for huge pages.
//go:build darwin || freebsd
//go:build darwin || freebsd || netbsd || dragonfly || solaris
package platform

View File

@ -1,10 +1,9 @@
//go:build (darwin || linux || freebsd) && !tinygo
//go:build (linux || darwin || freebsd || netbsd || dragonfly || solaris) && !tinygo
package platform
import (
"syscall"
"unsafe"
)
const (
@ -31,17 +30,3 @@ 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
}

View File

@ -1,4 +1,4 @@
//go:build !(darwin || linux || freebsd || windows) || tinygo
//go:build !(linux || darwin || freebsd || netbsd || dragonfly || solaris || windows) || tinygo
package platform

View File

@ -0,0 +1,22 @@
//go:build (freebsd || netbsd || dragonfly) && !tinygo
package platform
import (
"syscall"
"unsafe"
)
// MprotectRX is like syscall.Mprotect with RX permission, defined locally so that BSD 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
}

View File

@ -0,0 +1,10 @@
//go:build (linux || darwin) && !tinygo
package platform
import "syscall"
// MprotectRX is like syscall.Mprotect with RX permission.
func MprotectRX(b []byte) (err error) {
return syscall.Mprotect(b, syscall.PROT_READ|syscall.PROT_EXEC)
}

View File

@ -0,0 +1,9 @@
//go:build solaris && !tinygo
package platform
import "syscall"
func MprotectRX(b []byte) error {
return syscall.ENOTSUP
}

View File

@ -11,15 +11,16 @@ import (
// 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.
// CompilerSupported includes constraints here and also the assembler.
func CompilerSupported() bool {
switch runtime.GOOS {
case "darwin", "windows", "linux", "freebsd":
case "linux", "darwin", "freebsd", "netbsd", "dragonfly", "windows":
return archRequirementsVerified
case "solaris", "illumos":
return runtime.GOARCH == "amd64" && archRequirementsVerified
default:
return false
}
return archRequirementsVerified
}
// MmapCodeSegment copies the code into the executable region and returns the byte slice of the region.

View File

@ -2,6 +2,6 @@ package platform
// init verifies that the current CPU supports the required ARM64 features
func init() {
// No further checks currently needed.
archRequirementsVerified = true
// Ensure atomic instructions are supported.
archRequirementsVerified = CpuFeatures.Has(CpuFeatureArm64Atomic)
}