mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
The last remaining !go1.22 build is protecting the definition of
pkg/sync.maptype, which is a copy of runtime.maptype. We need to ensure these
definitions match so we can safely access the hasher field.
At its core, this CL achieves this check by ensuring that
unsafe.Offsetof(maptype{}.Hasher) matches the offset in the runtime version of
the type.
Several things happen along the way to achieve this:
* As of May 2023, runtime.maptype is actually a type alias for
internal/abi.MapType. checkoffset was failing to record the offsets because it
skipped type aliases for no good reason. Simply removing the type alias check
is sufficient to make type aliases work. (This part of the CL is technically
unnecessary because this CL ultimately references internal/abi.MapType
directly in anticipation of removal of the type alias. But there is no reason
not to allow type aliases).
* The checkconst / checkoffset regexp unintentionally does not allow / in
package paths, even though the rest of the package supports /. Fix this.
* checkconst was comparing the literal AST expression string against the
runtime value (i.e., "unsafe.Offsetof(maptype{}.Hasher)" vs "72", which fails
comparison. Switch to getting the resolved constant value from the type
checker.
* nogo/check.importer only loads package facts on direct import (stored in
importer.cache). If a package is not directly imported ImportPackageFact will
not find the facts. Typically packages need to ensure they directly depend on
packages they want facts from (e.g., pkg/sync has a dummy import of runtime in
runtime.go). This doesn't work for internal/abi because we cannot directly
import an internal package. Work around this as a hack by unconditionally
"importing" internal/abi when analyzing any package.
With regard to the last point, not that the nogo/defs.bzl nogo integration only
provides facts from the direct dependencies and the entire stdlib (since the
stdlib is analyzed as one bundle). So this trick only works for a stdlib
package. A bazel package indirect dependency would be missing facts altogether.
PiperOrigin-RevId: 549999084
138 lines
3.7 KiB
Go
138 lines
3.7 KiB
Go
// Copyright 2020 The gVisor Authors.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// //go:linkname directives type-checked by checklinkname.
|
|
// Runtime type copies checked by checkoffset.
|
|
|
|
package sync
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
// Goyield is runtime.goyield, which is similar to runtime.Gosched but only
|
|
// yields the processor to other goroutines already on the processor's
|
|
// runqueue.
|
|
//
|
|
//go:nosplit
|
|
func Goyield() {
|
|
goyield()
|
|
}
|
|
|
|
// Gopark is runtime.gopark. Gopark calls unlockf(pointer to runtime.g, lock);
|
|
// if unlockf returns true, Gopark blocks until Goready(pointer to runtime.g)
|
|
// is called. unlockf and its callees must be nosplit and norace, since stack
|
|
// splitting and race context are not available where it is called.
|
|
//
|
|
//go:nosplit
|
|
func Gopark(unlockf func(uintptr, unsafe.Pointer) bool, lock unsafe.Pointer, reason uint8, traceEv byte, traceskip int) {
|
|
gopark(unlockf, lock, reason, traceEv, traceskip)
|
|
}
|
|
|
|
//go:linkname gopark runtime.gopark
|
|
func gopark(unlockf func(uintptr, unsafe.Pointer) bool, lock unsafe.Pointer, reason uint8, traceEv byte, traceskip int)
|
|
|
|
//go:linkname wakep runtime.wakep
|
|
func wakep()
|
|
|
|
// Wakep is runtime.wakep.
|
|
//
|
|
//go:nosplit
|
|
func Wakep() {
|
|
// This is only supported if we can suppress the wakep called
|
|
// from Goready below, which is in certain architectures only.
|
|
if supportsWakeSuppression {
|
|
wakep()
|
|
}
|
|
}
|
|
|
|
//go:linkname goready runtime.goready
|
|
func goready(gp uintptr, traceskip int)
|
|
|
|
// Goready is runtime.goready.
|
|
//
|
|
// The additional wakep argument controls whether a new thread will be kicked to
|
|
// execute the P. This should be true in most circumstances. However, if the
|
|
// current thread is about to sleep, then this can be false for efficiency.
|
|
//
|
|
//go:nosplit
|
|
func Goready(gp uintptr, traceskip int, wakep bool) {
|
|
if supportsWakeSuppression && !wakep {
|
|
preGoReadyWakeSuppression()
|
|
}
|
|
goready(gp, traceskip)
|
|
if supportsWakeSuppression && !wakep {
|
|
postGoReadyWakeSuppression()
|
|
}
|
|
}
|
|
|
|
// Rand32 returns a non-cryptographically-secure random uint32.
|
|
func Rand32() uint32 {
|
|
return fastrand()
|
|
}
|
|
|
|
// Rand64 returns a non-cryptographically-secure random uint64.
|
|
func Rand64() uint64 {
|
|
return uint64(fastrand())<<32 | uint64(fastrand())
|
|
}
|
|
|
|
//go:linkname fastrand runtime.fastrand
|
|
func fastrand() uint32
|
|
|
|
// RandUintptr returns a non-cryptographically-secure random uintptr.
|
|
func RandUintptr() uintptr {
|
|
if unsafe.Sizeof(uintptr(0)) == 4 {
|
|
return uintptr(Rand32())
|
|
}
|
|
return uintptr(Rand64())
|
|
}
|
|
|
|
// MapKeyHasher returns a hash function for pointers of m's key type.
|
|
//
|
|
// Preconditions: m must be a map.
|
|
func MapKeyHasher(m any) func(unsafe.Pointer, uintptr) uintptr {
|
|
if rtyp := reflect.TypeOf(m); rtyp.Kind() != reflect.Map {
|
|
panic(fmt.Sprintf("sync.MapKeyHasher: m is %v, not map", rtyp))
|
|
}
|
|
mtyp := *(**maptype)(unsafe.Pointer(&m))
|
|
return mtyp.Hasher
|
|
}
|
|
|
|
// maptype is equivalent to the beginning of internal/abi.MapType.
|
|
type maptype struct {
|
|
size uintptr
|
|
ptrdata uintptr
|
|
hash uint32
|
|
tflag uint8
|
|
align uint8
|
|
fieldAlign uint8
|
|
kind uint8
|
|
equal func(unsafe.Pointer, unsafe.Pointer) bool
|
|
gcdata *byte
|
|
str int32
|
|
ptrToThis int32
|
|
key unsafe.Pointer
|
|
elem unsafe.Pointer
|
|
bucket unsafe.Pointer
|
|
Hasher func(unsafe.Pointer, uintptr) uintptr
|
|
// more fields
|
|
}
|
|
|
|
// These functions are only used within the sync package.
|
|
|
|
//go:linkname semacquire sync.runtime_Semacquire
|
|
func semacquire(addr *uint32)
|
|
|
|
//go:linkname semrelease sync.runtime_Semrelease
|
|
func semrelease(addr *uint32, handoff bool, skipframes int)
|
|
|
|
//go:linkname canSpin sync.runtime_canSpin
|
|
func canSpin(i int) bool
|
|
|
|
//go:linkname doSpin sync.runtime_doSpin
|
|
func doSpin()
|