| package gls |
| |
| // so, basically, we're going to encode integer tags in base-16 on the stack |
| |
| const ( |
| bitWidth = 4 |
| stackBatchSize = 16 |
| ) |
| |
| var ( |
| pc_lookup = make(map[uintptr]int8, 17) |
| mark_lookup [16]func(uint, func()) |
| ) |
| |
| func init() { |
| setEntries := func(f func(uint, func()), v int8) { |
| var ptr uintptr |
| f(0, func() { |
| ptr = findPtr() |
| }) |
| pc_lookup[ptr] = v |
| if v >= 0 { |
| mark_lookup[v] = f |
| } |
| } |
| setEntries(github_com_jtolds_gls_markS, -0x1) |
| setEntries(github_com_jtolds_gls_mark0, 0x0) |
| setEntries(github_com_jtolds_gls_mark1, 0x1) |
| setEntries(github_com_jtolds_gls_mark2, 0x2) |
| setEntries(github_com_jtolds_gls_mark3, 0x3) |
| setEntries(github_com_jtolds_gls_mark4, 0x4) |
| setEntries(github_com_jtolds_gls_mark5, 0x5) |
| setEntries(github_com_jtolds_gls_mark6, 0x6) |
| setEntries(github_com_jtolds_gls_mark7, 0x7) |
| setEntries(github_com_jtolds_gls_mark8, 0x8) |
| setEntries(github_com_jtolds_gls_mark9, 0x9) |
| setEntries(github_com_jtolds_gls_markA, 0xa) |
| setEntries(github_com_jtolds_gls_markB, 0xb) |
| setEntries(github_com_jtolds_gls_markC, 0xc) |
| setEntries(github_com_jtolds_gls_markD, 0xd) |
| setEntries(github_com_jtolds_gls_markE, 0xe) |
| setEntries(github_com_jtolds_gls_markF, 0xf) |
| } |
| |
| func addStackTag(tag uint, context_call func()) { |
| if context_call == nil { |
| return |
| } |
| github_com_jtolds_gls_markS(tag, context_call) |
| } |
| |
| // these private methods are named this horrendous name so gopherjs support |
| // is easier. it shouldn't add any runtime cost in non-js builds. |
| |
| //go:noinline |
| func github_com_jtolds_gls_markS(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark0(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark1(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark2(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark3(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark4(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark5(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark6(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark7(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark8(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_mark9(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_markA(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_markB(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_markC(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_markD(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_markE(tag uint, cb func()) { _m(tag, cb) } |
| |
| //go:noinline |
| func github_com_jtolds_gls_markF(tag uint, cb func()) { _m(tag, cb) } |
| |
| func _m(tag_remainder uint, cb func()) { |
| if tag_remainder == 0 { |
| cb() |
| } else { |
| mark_lookup[tag_remainder&0xf](tag_remainder>>bitWidth, cb) |
| } |
| } |
| |
| func readStackTag() (tag uint, ok bool) { |
| var current_tag uint |
| offset := 0 |
| for { |
| batch, next_offset := getStack(offset, stackBatchSize) |
| for _, pc := range batch { |
| val, ok := pc_lookup[pc] |
| if !ok { |
| continue |
| } |
| if val < 0 { |
| return current_tag, true |
| } |
| current_tag <<= bitWidth |
| current_tag += uint(val) |
| } |
| if next_offset == 0 { |
| break |
| } |
| offset = next_offset |
| } |
| return 0, false |
| } |
| |
| func (m *ContextManager) preventInlining() { |
| // dunno if findPtr or getStack are likely to get inlined in a future release |
| // of go, but if they are inlined and their callers are inlined, that could |
| // hork some things. let's do our best to explain to the compiler that we |
| // really don't want those two functions inlined by saying they could change |
| // at any time. assumes preventInlining doesn't get compiled out. |
| // this whole thing is probably overkill. |
| findPtr = m.values[0][0].(func() uintptr) |
| getStack = m.values[0][1].(func(int, int) ([]uintptr, int)) |
| } |