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  }