gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/evalop/ops.go (about)

     1  package evalop
     2  
     3  import (
     4  	"go/ast"
     5  	"go/constant"
     6  
     7  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf"
     8  )
     9  
    10  // Op is a stack machine opcode
    11  type Op interface {
    12  	depthCheck() (npop, npush int)
    13  }
    14  
    15  // PushCurg pushes the current goroutine on the stack.
    16  type PushCurg struct {
    17  }
    18  
    19  func (*PushCurg) depthCheck() (npop, npush int) { return 0, 1 }
    20  
    21  // PushFrameoff pushes the frame offset for the current frame on the stack.
    22  type PushFrameoff struct {
    23  }
    24  
    25  func (*PushFrameoff) depthCheck() (npop, npush int) { return 0, 1 }
    26  
    27  // PushThreadID pushes the ID of the current thread on the stack.
    28  type PushThreadID struct {
    29  }
    30  
    31  func (*PushThreadID) depthCheck() (npop, npush int) { return 0, 1 }
    32  
    33  // PushConst pushes a constant on the stack.
    34  type PushConst struct {
    35  	Value constant.Value
    36  }
    37  
    38  func (*PushConst) depthCheck() (npop, npush int) { return 0, 1 }
    39  
    40  // PushLocal pushes the local variable with the given name on the stack.
    41  type PushLocal struct {
    42  	Name  string
    43  	Frame int64
    44  }
    45  
    46  func (*PushLocal) depthCheck() (npop, npush int) { return 0, 1 }
    47  
    48  // PushNil pushes an untyped nil on the stack.
    49  type PushNil struct {
    50  }
    51  
    52  func (*PushNil) depthCheck() (npop, npush int) { return 0, 1 }
    53  
    54  // PushRegister pushes the CPU register Regnum on the stack.
    55  type PushRegister struct {
    56  	Regnum  int
    57  	Regname string
    58  }
    59  
    60  func (*PushRegister) depthCheck() (npop, npush int) { return 0, 1 }
    61  
    62  // PushPackageVar pushes a package variable on the stack.
    63  type PushPackageVar struct {
    64  	PkgName, Name string // if PkgName == "" use current function's package
    65  }
    66  
    67  func (*PushPackageVar) depthCheck() (npop, npush int) { return 0, 1 }
    68  
    69  // PushLen pushes the length of the variable at the top of the stack into
    70  // the stack.
    71  type PushLen struct {
    72  }
    73  
    74  func (*PushLen) depthCheck() (npop, npush int) { return 1, 2 }
    75  
    76  // Select replaces the topmost stack variable v with v.Name.
    77  type Select struct {
    78  	Name string
    79  }
    80  
    81  func (*Select) depthCheck() (npop, npush int) { return 1, 1 }
    82  
    83  // TypeAssert replaces the topmost stack variable v with v.(DwarfType).
    84  type TypeAssert struct {
    85  	DwarfType godwarf.Type
    86  	Node      *ast.TypeAssertExpr
    87  }
    88  
    89  func (*TypeAssert) depthCheck() (npop, npush int) { return 1, 1 }
    90  
    91  // PointerDeref replaces the topmost stack variable v with *v.
    92  type PointerDeref struct {
    93  	Node *ast.StarExpr
    94  }
    95  
    96  func (*PointerDeref) depthCheck() (npop, npush int) { return 1, 1 }
    97  
    98  // Unary applies the given unary operator to the topmost stack variable.
    99  type Unary struct {
   100  	Node *ast.UnaryExpr
   101  }
   102  
   103  func (*Unary) depthCheck() (npop, npush int) { return 1, 1 }
   104  
   105  // AddrOf replaces the topmost stack variable v with &v.
   106  type AddrOf struct {
   107  	Node *ast.UnaryExpr
   108  }
   109  
   110  func (*AddrOf) depthCheck() (npop, npush int) { return 1, 1 }
   111  
   112  // TypeCast replaces the topmost stack variable v with (DwarfType)(v).
   113  type TypeCast struct {
   114  	DwarfType godwarf.Type
   115  	Node      *ast.CallExpr
   116  }
   117  
   118  func (*TypeCast) depthCheck() (npop, npush int) { return 1, 1 }
   119  
   120  // Reslice implements a reslice operation.
   121  // If HasHigh is set it pops three variables, low, high and v, and pushes
   122  // v[low:high].
   123  // Otherwise it pops two variables, low and v, and pushes v[low:].
   124  // If TrustLen is set when the variable resulting from the reslice is loaded it will be fully loaded.
   125  type Reslice struct {
   126  	HasHigh  bool
   127  	TrustLen bool
   128  	Node     *ast.SliceExpr
   129  }
   130  
   131  func (op *Reslice) depthCheck() (npop, npush int) {
   132  	if op.HasHigh {
   133  		return 3, 1
   134  	} else {
   135  		return 2, 1
   136  	}
   137  }
   138  
   139  // Index pops two variables, idx and v, and pushes v[idx].
   140  type Index struct {
   141  	Node *ast.IndexExpr
   142  }
   143  
   144  func (*Index) depthCheck() (npop, npush int) { return 2, 1 }
   145  
   146  // Jump looks at the topmost stack variable and if it satisfies the
   147  // condition specified by When it jumps to the stack machine instruction at
   148  // Target+1.
   149  // If Pop is set the topmost stack variable is also popped.
   150  type Jump struct {
   151  	When   JumpCond
   152  	Pop    bool
   153  	Target int
   154  	Node   ast.Expr
   155  }
   156  
   157  func (jmpif *Jump) depthCheck() (npop, npush int) {
   158  	if jmpif.Pop {
   159  		return 1, 0
   160  	}
   161  	return 0, 0
   162  }
   163  
   164  // JumpCond specifies a condition for the Jump instruction.
   165  type JumpCond uint8
   166  
   167  const (
   168  	JumpIfFalse JumpCond = iota
   169  	JumpIfTrue
   170  	JumpIfAllocStringChecksFail
   171  )
   172  
   173  // Binary pops two variables from the stack, applies the specified binary
   174  // operator to them and pushes the result back on the stack.
   175  type Binary struct {
   176  	Node *ast.BinaryExpr
   177  }
   178  
   179  func (*Binary) depthCheck() (npop, npush int) { return 2, 1 }
   180  
   181  // BoolToConst pops the topmost variable from the stack, which must be a
   182  // boolean variable, and converts it to a constant.
   183  type BoolToConst struct {
   184  }
   185  
   186  func (*BoolToConst) depthCheck() (npop, npush int) { return 1, 1 }
   187  
   188  // Pop removes the topmost variable from the stack.
   189  type Pop struct {
   190  }
   191  
   192  func (*Pop) depthCheck() (npop, npush int) { return 1, 0 }
   193  
   194  // BuiltinCall pops len(Args) argument from the stack, calls the specified
   195  // builtin on them and pushes the result back on the stack.
   196  type BuiltinCall struct {
   197  	Name string
   198  	Args []ast.Expr
   199  }
   200  
   201  func (bc *BuiltinCall) depthCheck() (npop, npush int) {
   202  	return len(bc.Args), 1
   203  }
   204  
   205  // CallInjectionStart starts call injection by calling
   206  // runtime.debugCallVn.
   207  type CallInjectionStart struct {
   208  	id      int  // identifier for all the call injection instructions that belong to the same sequence, this only exists to make reading listings easier
   209  	HasFunc bool // target function already pushed on the stack
   210  	Node    *ast.CallExpr
   211  }
   212  
   213  func (*CallInjectionStart) depthCheck() (npop, npush int) { return 0, 1 }
   214  
   215  // CallInjectionSetTarget starts the call injection, after
   216  // runtime.debugCallVn set up the stack for us, by copying the entry point
   217  // of the function, setting the closure register and copying the receiver.
   218  type CallInjectionSetTarget struct {
   219  	id int
   220  }
   221  
   222  func (*CallInjectionSetTarget) depthCheck() (npop, npush int) { return 1, 0 }
   223  
   224  // CallInjectionCopyArg copies one argument for call injection.
   225  type CallInjectionCopyArg struct {
   226  	id      int
   227  	ArgNum  int
   228  	ArgExpr ast.Expr
   229  }
   230  
   231  func (*CallInjectionCopyArg) depthCheck() (npop, npush int) { return 1, 0 }
   232  
   233  // CallInjectionComplete resumes target execution so that the injected call can run.
   234  type CallInjectionComplete struct {
   235  	id int
   236  }
   237  
   238  func (*CallInjectionComplete) depthCheck() (npop, npush int) { return 0, 1 }
   239  
   240  // CallInjectionStartSpecial starts call injection for a function with a
   241  // name and arguments known at compile time.
   242  type CallInjectionStartSpecial struct {
   243  	id     int
   244  	FnName string
   245  	ArgAst []ast.Expr
   246  }
   247  
   248  func (*CallInjectionStartSpecial) depthCheck() (npop, npush int) { return 0, 1 }
   249  
   250  // ConvertAllocToString pops two variables from the stack, a constant string
   251  // and the return value of runtime.mallocgc (mallocv), copies the contents
   252  // of the string at the address in mallocv and pushes on the stack a new
   253  // string value that uses the backing storage of mallocv.
   254  type ConvertAllocToString struct {
   255  }
   256  
   257  func (*ConvertAllocToString) depthCheck() (npop, npush int) { return 2, 1 }
   258  
   259  // SetValue pops to variables from the stack, lhv and rhv, and sets lhv to
   260  // rhv.
   261  type SetValue struct {
   262  	lhe, Rhe ast.Expr
   263  }
   264  
   265  func (*SetValue) depthCheck() (npop, npush int) { return 2, 0 }