stack_tags.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package gls
  2. // so, basically, we're going to encode integer tags in base-16 on the stack
  3. const (
  4. bitWidth = 4
  5. stackBatchSize = 16
  6. )
  7. var (
  8. pc_lookup = make(map[uintptr]int8, 17)
  9. mark_lookup [16]func(uint, func())
  10. )
  11. func init() {
  12. setEntries := func(f func(uint, func()), v int8) {
  13. var ptr uintptr
  14. f(0, func() {
  15. ptr = findPtr()
  16. })
  17. pc_lookup[ptr] = v
  18. if v >= 0 {
  19. mark_lookup[v] = f
  20. }
  21. }
  22. setEntries(github_com_jtolds_gls_markS, -0x1)
  23. setEntries(github_com_jtolds_gls_mark0, 0x0)
  24. setEntries(github_com_jtolds_gls_mark1, 0x1)
  25. setEntries(github_com_jtolds_gls_mark2, 0x2)
  26. setEntries(github_com_jtolds_gls_mark3, 0x3)
  27. setEntries(github_com_jtolds_gls_mark4, 0x4)
  28. setEntries(github_com_jtolds_gls_mark5, 0x5)
  29. setEntries(github_com_jtolds_gls_mark6, 0x6)
  30. setEntries(github_com_jtolds_gls_mark7, 0x7)
  31. setEntries(github_com_jtolds_gls_mark8, 0x8)
  32. setEntries(github_com_jtolds_gls_mark9, 0x9)
  33. setEntries(github_com_jtolds_gls_markA, 0xa)
  34. setEntries(github_com_jtolds_gls_markB, 0xb)
  35. setEntries(github_com_jtolds_gls_markC, 0xc)
  36. setEntries(github_com_jtolds_gls_markD, 0xd)
  37. setEntries(github_com_jtolds_gls_markE, 0xe)
  38. setEntries(github_com_jtolds_gls_markF, 0xf)
  39. }
  40. func addStackTag(tag uint, context_call func()) {
  41. if context_call == nil {
  42. return
  43. }
  44. github_com_jtolds_gls_markS(tag, context_call)
  45. }
  46. // these private methods are named this horrendous name so gopherjs support
  47. // is easier. it shouldn't add any runtime cost in non-js builds.
  48. //go:noinline
  49. func github_com_jtolds_gls_markS(tag uint, cb func()) { _m(tag, cb) }
  50. //go:noinline
  51. func github_com_jtolds_gls_mark0(tag uint, cb func()) { _m(tag, cb) }
  52. //go:noinline
  53. func github_com_jtolds_gls_mark1(tag uint, cb func()) { _m(tag, cb) }
  54. //go:noinline
  55. func github_com_jtolds_gls_mark2(tag uint, cb func()) { _m(tag, cb) }
  56. //go:noinline
  57. func github_com_jtolds_gls_mark3(tag uint, cb func()) { _m(tag, cb) }
  58. //go:noinline
  59. func github_com_jtolds_gls_mark4(tag uint, cb func()) { _m(tag, cb) }
  60. //go:noinline
  61. func github_com_jtolds_gls_mark5(tag uint, cb func()) { _m(tag, cb) }
  62. //go:noinline
  63. func github_com_jtolds_gls_mark6(tag uint, cb func()) { _m(tag, cb) }
  64. //go:noinline
  65. func github_com_jtolds_gls_mark7(tag uint, cb func()) { _m(tag, cb) }
  66. //go:noinline
  67. func github_com_jtolds_gls_mark8(tag uint, cb func()) { _m(tag, cb) }
  68. //go:noinline
  69. func github_com_jtolds_gls_mark9(tag uint, cb func()) { _m(tag, cb) }
  70. //go:noinline
  71. func github_com_jtolds_gls_markA(tag uint, cb func()) { _m(tag, cb) }
  72. //go:noinline
  73. func github_com_jtolds_gls_markB(tag uint, cb func()) { _m(tag, cb) }
  74. //go:noinline
  75. func github_com_jtolds_gls_markC(tag uint, cb func()) { _m(tag, cb) }
  76. //go:noinline
  77. func github_com_jtolds_gls_markD(tag uint, cb func()) { _m(tag, cb) }
  78. //go:noinline
  79. func github_com_jtolds_gls_markE(tag uint, cb func()) { _m(tag, cb) }
  80. //go:noinline
  81. func github_com_jtolds_gls_markF(tag uint, cb func()) { _m(tag, cb) }
  82. func _m(tag_remainder uint, cb func()) {
  83. if tag_remainder == 0 {
  84. cb()
  85. } else {
  86. mark_lookup[tag_remainder&0xf](tag_remainder>>bitWidth, cb)
  87. }
  88. }
  89. func readStackTag() (tag uint, ok bool) {
  90. var current_tag uint
  91. offset := 0
  92. for {
  93. batch, next_offset := getStack(offset, stackBatchSize)
  94. for _, pc := range batch {
  95. val, ok := pc_lookup[pc]
  96. if !ok {
  97. continue
  98. }
  99. if val < 0 {
  100. return current_tag, true
  101. }
  102. current_tag <<= bitWidth
  103. current_tag += uint(val)
  104. }
  105. if next_offset == 0 {
  106. break
  107. }
  108. offset = next_offset
  109. }
  110. return 0, false
  111. }
  112. func (m *ContextManager) preventInlining() {
  113. // dunno if findPtr or getStack are likely to get inlined in a future release
  114. // of go, but if they are inlined and their callers are inlined, that could
  115. // hork some things. let's do our best to explain to the compiler that we
  116. // really don't want those two functions inlined by saying they could change
  117. // at any time. assumes preventInlining doesn't get compiled out.
  118. // this whole thing is probably overkill.
  119. findPtr = m.values[0][0].(func() uintptr)
  120. getStack = m.values[0][1].(func(int, int) ([]uintptr, int))
  121. }