96
attr.go
Normal file
96
attr.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package avo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/bits"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Attribute represents TEXT or DATA flags.
|
||||||
|
type Attribute uint16
|
||||||
|
|
||||||
|
// Reference: https://github.com/golang/go/blob/c043fc4f655ce34f67a0e7fe2833139f6313a3f0/src/runtime/textflag.h#L11-L34
|
||||||
|
//
|
||||||
|
// // Don't profile the marked routine. This flag is deprecated.
|
||||||
|
// #define NOPROF 1
|
||||||
|
// // It is ok for the linker to get multiple of these symbols. It will
|
||||||
|
// // pick one of the duplicates to use.
|
||||||
|
// #define DUPOK 2
|
||||||
|
// // Don't insert stack check preamble.
|
||||||
|
// #define NOSPLIT 4
|
||||||
|
// // Put this data in a read-only section.
|
||||||
|
// #define RODATA 8
|
||||||
|
// // This data contains no pointers.
|
||||||
|
// #define NOPTR 16
|
||||||
|
// // This is a wrapper function and should not count as disabling 'recover'.
|
||||||
|
// #define WRAPPER 32
|
||||||
|
// // This function uses its incoming context register.
|
||||||
|
// #define NEEDCTXT 64
|
||||||
|
// // Allocate a word of thread local storage and store the offset from the
|
||||||
|
// // thread local base to the thread local storage in this variable.
|
||||||
|
// #define TLSBSS 256
|
||||||
|
// // Do not insert instructions to allocate a stack frame for this function.
|
||||||
|
// // Only valid on functions that declare a frame size of 0.
|
||||||
|
// // TODO(mwhudson): only implemented for ppc64x at present.
|
||||||
|
// #define NOFRAME 512
|
||||||
|
// // Function can call reflect.Type.Method or reflect.Type.MethodByName.
|
||||||
|
// #define REFLECTMETHOD = 1024
|
||||||
|
//
|
||||||
|
const (
|
||||||
|
NOPROF Attribute = 1 << iota
|
||||||
|
DUPOK
|
||||||
|
NOSPLIT
|
||||||
|
RODATA
|
||||||
|
NOPTR
|
||||||
|
WRAPPER
|
||||||
|
NEEDCTXT
|
||||||
|
_
|
||||||
|
TLSBSS
|
||||||
|
NOFRAME
|
||||||
|
REFLECTMETHOD
|
||||||
|
)
|
||||||
|
|
||||||
|
// Asm returns a representation of the attributes in assembly syntax. This may use macros from "textflags.h"; see ContainsTextFlags() to determine if this header is required.
|
||||||
|
func (a Attribute) Asm() string {
|
||||||
|
parts, rest := a.split()
|
||||||
|
if len(parts) == 0 || rest != 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%d", rest))
|
||||||
|
}
|
||||||
|
return strings.Join(parts, "|")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsTextFlags() returns whether the Asm() representation requires macros in "textflags.h".
|
||||||
|
func (a Attribute) ContainsTextFlags() bool {
|
||||||
|
flags, _ := a.split()
|
||||||
|
return len(flags) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// split splits a into known flags and any remaining bits.
|
||||||
|
func (a Attribute) split() ([]string, Attribute) {
|
||||||
|
var flags []string
|
||||||
|
var rest Attribute
|
||||||
|
for a != 0 {
|
||||||
|
i := uint(bits.TrailingZeros16(uint16(a)))
|
||||||
|
bit := Attribute(1) << uint(i)
|
||||||
|
if flag := attrname[bit]; flag != "" {
|
||||||
|
flags = append(flags, flag)
|
||||||
|
} else {
|
||||||
|
rest |= bit
|
||||||
|
}
|
||||||
|
a ^= bit
|
||||||
|
}
|
||||||
|
return flags, rest
|
||||||
|
}
|
||||||
|
|
||||||
|
var attrname = map[Attribute]string{
|
||||||
|
NOPROF: "NOPROF",
|
||||||
|
DUPOK: "DUPOK",
|
||||||
|
NOSPLIT: "NOSPLIT",
|
||||||
|
RODATA: "RODATA",
|
||||||
|
NOPTR: "NOPTR",
|
||||||
|
WRAPPER: "WRAPPER",
|
||||||
|
NEEDCTXT: "NEEDCTXT",
|
||||||
|
TLSBSS: "TLSBSS",
|
||||||
|
NOFRAME: "NOFRAME",
|
||||||
|
REFLECTMETHOD: "REFLECTMETHOD",
|
||||||
|
}
|
||||||
42
attr_test.go
Normal file
42
attr_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package avo
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestAttributeAsm(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Attribute Attribute
|
||||||
|
Expect string
|
||||||
|
}{
|
||||||
|
{0, "0"},
|
||||||
|
{32768, "32768"},
|
||||||
|
{1, "NOPROF"},
|
||||||
|
{DUPOK, "DUPOK"},
|
||||||
|
{RODATA | NOSPLIT, "NOSPLIT|RODATA"},
|
||||||
|
{WRAPPER | 16384 | NOPTR, "NOPTR|WRAPPER|16384"},
|
||||||
|
{NEEDCTXT + NOFRAME + TLSBSS + REFLECTMETHOD, "NEEDCTXT|TLSBSS|NOFRAME|REFLECTMETHOD"},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
got := c.Attribute.Asm()
|
||||||
|
if got != c.Expect {
|
||||||
|
t.Errorf("Attribute(%d).Asm() = %#v; expect %#v", c.Attribute, got, c.Expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttributeContainsTextFlags(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Attribute Attribute
|
||||||
|
Expect bool
|
||||||
|
}{
|
||||||
|
{0, false},
|
||||||
|
{32768, false},
|
||||||
|
{1, true},
|
||||||
|
{DUPOK, true},
|
||||||
|
{WRAPPER | 16384 | NOPTR, true},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
if c.Attribute.ContainsTextFlags() != c.Expect {
|
||||||
|
t.Errorf("%s: ContainsTextFlags() expected %#v", c.Attribute.Asm(), c.Expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user