github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/debughooks.go (about) 1 package runtime 2 3 /* 4 Debug hooks. For call/return, it's a bit complicated. The logic is split 5 between 6 7 - LuaCont.RunInThread(): when exiting, a call / tailcall / return event is 8 emitted 9 - GoCont.RuntInThread(): when exiting, a return event is emitted 10 - Thread.RunContinuation: at the start (before the loop), a call event is 11 emitted 12 13 It's unfortunate it has to be split like this but I cannot find a better 14 approach. 15 */ 16 17 // DebugHookFlags is the type of representing a set of debug hooks. 18 type DebugHookFlags uint8 19 20 const ( 21 hookFlagInHook DebugHookFlags = 1 << iota // This flag allows knowing when we are in hook callback 22 HookFlagCall // call hook 23 HookFlagReturn // return hook 24 HookFlagLine // line hook 25 HookFlagCount // count hook 26 ) 27 28 // DebugHooks contains data specifying a debug hooks configuration. 29 type DebugHooks struct { 30 DebugHookFlags DebugHookFlags // hooks enabled 31 HookLineCount int // number of lines for count hook 32 Hook Value // The hook callback 33 } 34 35 func (h *DebugHooks) callHook(t *Thread, c Cont, args ...Value) error { 36 if h.DebugHookFlags&hookFlagInHook != 0 || c == nil { 37 return nil 38 } 39 h.DebugHookFlags |= hookFlagInHook 40 defer func() { h.DebugHookFlags &= ^hookFlagInHook }() 41 term := NewTerminationWith(c, 0, false) 42 return Call(t, h.Hook, args, term) 43 } 44 45 // SetupHooks configures the debug hooks to use. It does nothing if we are in a 46 // hook callback. 47 func (h *DebugHooks) SetupHooks(newHooks DebugHooks) { 48 if h.DebugHookFlags&hookFlagInHook != 0 { 49 return 50 } 51 *h = newHooks 52 } 53 54 var ( 55 callHookString = StringValue("call") 56 tailCallHookString = StringValue("tail call") 57 returnHookString = StringValue("return") 58 lineHookString = StringValue("line") 59 ) 60 61 // Important for this function to inline. 62 func (h *DebugHooks) triggerCall(t *Thread, c Cont) error { 63 if h.DebugHookFlags&HookFlagCall == 0 { 64 return nil 65 } 66 return h.callHook(t, c, callHookString) 67 } 68 69 // Important for this function to inline. 70 func (h *DebugHooks) triggerTailCall(t *Thread, c Cont) error { 71 if h.DebugHookFlags&HookFlagCall == 0 { 72 return nil 73 } 74 return h.callHook(t, c, tailCallHookString) 75 } 76 77 // Important for this function to inline. 78 func (h *DebugHooks) triggerReturn(t *Thread, c Cont) error { 79 if h.DebugHookFlags&HookFlagReturn == 0 { 80 return nil 81 } 82 return h.callHook(t, c, returnHookString) 83 } 84 85 // Important for this function to inline. 86 func (h *DebugHooks) triggerLine(t *Thread, c Cont, l int32) error { 87 if h.DebugHookFlags&HookFlagLine == 0 || l <= 0 { 88 return nil 89 } 90 return h.callHook(t, c, lineHookString, IntValue(int64(l))) 91 } 92 93 // Important for this function to inline. 94 func (h *DebugHooks) areFlagsEnabled(flags DebugHookFlags) bool { 95 return h.DebugHookFlags&hookFlagInHook == 0 && h.DebugHookFlags&flags != 0 96 }