Skip to content

Commit

Permalink
all: merge flag* const info internaal/abi
Browse files Browse the repository at this point in the history
  • Loading branch information
qiulaidongfeng committed Feb 13, 2024
1 parent 2a59041 commit 4d76a72
Show file tree
Hide file tree
Showing 11 changed files with 475 additions and 499 deletions.
104 changes: 104 additions & 0 deletions src/internal/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,107 @@ func (b *IntArgRegBitmap) Set(i int) {
func (b *IntArgRegBitmap) Get(i int) bool {
return b[i/8]&(uint8(1)<<(i%8)) != 0
}

type Flag uintptr

const (
FlagKindWidth Flag = 5 // there are 27 kinds
FlagKindMask Flag = 1<<FlagKindWidth - 1
FlagStickyRO Flag = 1 << 5
FlagEmbedRO Flag = 1 << 6
FlagIndir Flag = 1 << 7
FlagAddr Flag = 1 << 8
FlagMethod Flag = 1 << 9
FlagMethodShift Flag = 10
FlagRO Flag = FlagStickyRO | FlagEmbedRO
)

func (f Flag) Kind() Kind {
return Kind(f & FlagKindMask)
}

func (f Flag) Ro() Flag {
if f&FlagRO != 0 {
return FlagStickyRO
}
return 0
}

// mustBe panics if f's kind is not expected.
// Making this a method on flag instead of on Value
// (and embedding flag in Value) means that we can write
// the very clear v.mustBe(Bool) and have it compile into
// v.flag.mustBe(Bool), which will only bother to copy the
// single important word for the receiver.
func (f Flag) MustBe(expected Kind) {
// TODO(mvdan): use f.kind() again once mid-stack inlining gets better
if Kind(f&FlagKindMask) != expected {
panic(&ValueError{valueMethodName(), Kind(f.Kind())})
}
}

// mustBeExported panics if f records that the value was obtained using
// an unexported field.
func (f Flag) MustBeExported() {
if f == 0 || f&FlagRO != 0 {
f.MustBeExportedSlow()
}
}

func (f Flag) MustBeExportedSlow() {
if f == 0 {
panic(&ValueError{valueMethodName(), Invalid})
}
if f&FlagRO != 0 {
panic("reflect: " + valueMethodName() + " using value obtained using unexported field")
}
}

// mustBeAssignable panics if f records that the value is not assignable,
// which is to say that either it was obtained using an unexported field
// or it is not addressable.
func (f Flag) MustBeAssignable() {
if f&FlagRO != 0 || f&FlagAddr == 0 {
f.MustBeAssignableSlow()
}
}

func (f Flag) MustBeAssignableSlow() {
if f == 0 {
panic(&ValueError{valueMethodName(), Invalid})
}
// Assignable if addressable and not read-only.
if f&FlagRO != 0 {
panic("reflect: " + valueMethodName() + " using value obtained using unexported field")
}
if f&FlagAddr == 0 {
panic("reflect: " + valueMethodName() + " using unaddressable value")
}
}

// Force slow panicking path not inlined, so it won't add to the
// inlining budget of the caller.
// TODO: undo when the inliner is no longer bottom-up only.
//
//go:noinline
func (f Flag) PanicNotMap() {
f.MustBe(Map)
}

// A ValueError occurs when a Value method is invoked on
// a [Value] that does not support it. Such cases are documented
// in the description of each method.
type ValueError struct {
Method string
Kind Kind
}

func (e *ValueError) Error() string {
if e.Kind == 0 {
return "reflect: call of " + e.Method + " on zero Value"
}
return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
}

//go:linkname valueMethodName runtime.valueMethodName
func valueMethodName() string
15 changes: 8 additions & 7 deletions src/internal/reflectlite/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
package reflectlite

import (
"internal/abi"
"unsafe"
)

// Field returns the i'th field of the struct v.
// It panics if v's Kind is not Struct or i is out of range.
func Field(v Value, i int) Value {
if v.kind() != Struct {
panic(&ValueError{"reflect.Value.Field", v.kind()})
if v.Kind() != Struct {
panic(&ValueError{"reflect.Value.Field", v.Kind()})
}
tt := (*structType)(unsafe.Pointer(v.typ()))
if uint(i) >= uint(len(tt.Fields)) {
Expand All @@ -22,13 +23,13 @@ func Field(v Value, i int) Value {
typ := field.Typ

// Inherit permission bits from v, but clear flagEmbedRO.
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
fl := v.Flag&(abi.FlagStickyRO|abi.FlagIndir|abi.FlagAddr) | abi.Flag(typ.Kind())
// Using an unexported field forces flagRO.
if !field.Name.IsExported() {
if field.Embedded() {
fl |= flagEmbedRO
fl |= abi.FlagEmbedRO
} else {
fl |= flagStickyRO
fl |= abi.FlagStickyRO
}
}
// Either flagIndir is set and v.ptr points at struct,
Expand Down Expand Up @@ -69,9 +70,9 @@ func Zero(typ Type) Value {
panic("reflect: Zero(nil)")
}
t := typ.common()
fl := flag(t.Kind())
fl := abi.Flag(t.Kind())
if ifaceIndir(t) {
return Value{t, unsafe_New(t), fl | flagIndir}
return Value{t, unsafe_New(t), fl | abi.FlagIndir}
}
return Value{t, nil, fl}
}
Expand Down
Loading

0 comments on commit 4d76a72

Please sign in to comment.