abi_amd64.go raw

   1  /*
   2   * Copyright 2022 ByteDance Inc.
   3   *
   4   * Licensed under the Apache License, Version 2.0 (the "License");
   5   * you may not use this file except in compliance with the License.
   6   * You may obtain a copy of the License at
   7   *
   8   *     http://www.apache.org/licenses/LICENSE-2.0
   9   *
  10   * Unless required by applicable law or agreed to in writing, software
  11   * distributed under the License is distributed on an "AS IS" BASIS,
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13   * See the License for the specific language governing permissions and
  14   * limitations under the License.
  15   */
  16  
  17  package abi
  18  
  19  import (
  20  	"fmt"
  21  	"reflect"
  22  	"unsafe"
  23  
  24  	x64 "github.com/bytedance/sonic/loader/internal/iasm/x86_64"
  25  )
  26  
  27  type (
  28  	Register      = x64.Register
  29  	Register64    = x64.Register64
  30  	XMMRegister   = x64.XMMRegister
  31  	Program       = x64.Program
  32  	MemoryOperand = x64.MemoryOperand
  33  	Label         = x64.Label
  34  )
  35  
  36  var (
  37  	Ptr         = x64.Ptr
  38  	DefaultArch = x64.DefaultArch
  39  	CreateLabel = x64.CreateLabel
  40  )
  41  
  42  const (
  43  	RAX = x64.RAX
  44  	RSP = x64.RSP
  45  	RBP = x64.RBP
  46  	R12 = x64.R12
  47  	R14 = x64.R14
  48  	R15 = x64.R15
  49  )
  50  
  51  const (
  52  	PtrSize  = 8 // pointer size
  53  	PtrAlign = 8 // pointer alignment
  54  )
  55  
  56  var iregOrderC = []Register{
  57  	x64.RDI,
  58  	x64.RSI,
  59  	x64.RDX,
  60  	x64.RCX,
  61  	x64.R8,
  62  	x64.R9,
  63  }
  64  
  65  var xregOrderC = []Register{
  66  	x64.XMM0,
  67  	x64.XMM1,
  68  	x64.XMM2,
  69  	x64.XMM3,
  70  	x64.XMM4,
  71  	x64.XMM5,
  72  	x64.XMM6,
  73  	x64.XMM7,
  74  }
  75  
  76  var (
  77  	intType = reflect.TypeOf(0)
  78  	ptrType = reflect.TypeOf(unsafe.Pointer(nil))
  79  )
  80  
  81  func (self *Frame) argv(i int) *MemoryOperand {
  82  	return Ptr(RSP, int32(self.Prev()+self.desc.Args[i].Mem))
  83  }
  84  
  85  // spillv is used for growstack spill registers
  86  func (self *Frame) spillv(i int) *MemoryOperand {
  87  	// remain one slot for caller return pc
  88  	return Ptr(RSP, PtrSize+int32(self.desc.Args[i].Mem))
  89  }
  90  
  91  func (self *Frame) retv(i int) *MemoryOperand {
  92  	return Ptr(RSP, int32(self.Prev()+self.desc.Rets[i].Mem))
  93  }
  94  
  95  func (self *Frame) resv(i int) *MemoryOperand {
  96  	return Ptr(RSP, int32(self.Offs()-uint32((i+1)*PtrSize)))
  97  }
  98  
  99  func (self *Frame) emitGrowStack(p *Program, entry *Label) {
 100  	// spill all register arguments
 101  	for i, v := range self.desc.Args {
 102  		if v.InRegister {
 103  			if v.IsFloat == floatKind64 {
 104  				p.MOVSD(v.Reg, self.spillv(i))
 105  			} else if v.IsFloat == floatKind32 {
 106  				p.MOVSS(v.Reg, self.spillv(i))
 107  			} else {
 108  				p.MOVQ(v.Reg, self.spillv(i))
 109  			}
 110  		}
 111  	}
 112  
 113  	// call runtime.morestack_noctxt
 114  	p.MOVQ(F_morestack_noctxt, R12)
 115  	p.CALLQ(R12)
 116  	// load all register arguments
 117  	for i, v := range self.desc.Args {
 118  		if v.InRegister {
 119  			if v.IsFloat == floatKind64 {
 120  				p.MOVSD(self.spillv(i), v.Reg)
 121  			} else if v.IsFloat == floatKind32 {
 122  				p.MOVSS(self.spillv(i), v.Reg)
 123  			} else {
 124  				p.MOVQ(self.spillv(i), v.Reg)
 125  			}
 126  		}
 127  	}
 128  
 129  	// jump back to the function entry
 130  	p.JMP(entry)
 131  }
 132  
 133  func (self *Frame) GrowStackTextSize() uint32 {
 134  	p := DefaultArch.CreateProgram()
 135  	// spill all register arguments
 136  	for i, v := range self.desc.Args {
 137  		if v.InRegister {
 138  			if v.IsFloat == floatKind64 {
 139  				p.MOVSD(v.Reg, self.spillv(i))
 140  			} else if v.IsFloat == floatKind32 {
 141  				p.MOVSS(v.Reg, self.spillv(i))
 142  			} else {
 143  				p.MOVQ(v.Reg, self.spillv(i))
 144  			}
 145  		}
 146  	}
 147  
 148  	// call runtime.morestack_noctxt
 149  	p.MOVQ(F_morestack_noctxt, R12)
 150  	p.CALLQ(R12)
 151  	// load all register arguments
 152  	for i, v := range self.desc.Args {
 153  		if v.InRegister {
 154  			if v.IsFloat == floatKind64 {
 155  				p.MOVSD(self.spillv(i), v.Reg)
 156  			} else if v.IsFloat == floatKind32 {
 157  				p.MOVSS(self.spillv(i), v.Reg)
 158  			} else {
 159  				p.MOVQ(self.spillv(i), v.Reg)
 160  			}
 161  		}
 162  	}
 163  
 164  	// jump back to the function entry
 165  	l := CreateLabel("")
 166  	p.Link(l)
 167  	p.JMP(l)
 168  
 169  	return uint32(len(p.Assemble(0)))
 170  }
 171  
 172  func (self *Frame) emitPrologue(p *Program) {
 173  	p.SUBQ(self.Size(), RSP)
 174  	p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
 175  	p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
 176  }
 177  
 178  func (self *Frame) emitEpilogue(p *Program) {
 179  	p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
 180  	p.ADDQ(self.Size(), RSP)
 181  	p.RET()
 182  }
 183  
 184  func (self *Frame) emitReserveRegs(p *Program) {
 185  	// spill reserved registers
 186  	for i, r := range ReservedRegs(self.ccall) {
 187  		switch r.(type) {
 188  		case Register64:
 189  			p.MOVQ(r, self.resv(i))
 190  		case XMMRegister:
 191  			p.MOVSD(r, self.resv(i))
 192  		default:
 193  			panic(fmt.Sprintf("unsupported register type %t to reserve", r))
 194  		}
 195  	}
 196  }
 197  
 198  func (self *Frame) emitSpillPtrs(p *Program) {
 199  	// spill pointer argument registers
 200  	for i, r := range self.desc.Args {
 201  		if r.InRegister && r.IsPointer {
 202  			p.MOVQ(r.Reg, self.argv(i))
 203  		}
 204  	}
 205  }
 206  
 207  func (self *Frame) emitClearPtrs(p *Program) {
 208  	// spill pointer argument registers
 209  	for i, r := range self.desc.Args {
 210  		if r.InRegister && r.IsPointer {
 211  			p.MOVQ(int64(0), self.argv(i))
 212  		}
 213  	}
 214  }
 215  
 216  func (self *Frame) emitCallC(p *Program, addr uintptr) {
 217  	p.MOVQ(addr, RAX)
 218  	p.CALLQ(RAX)
 219  }
 220  
 221  type floatKind uint8
 222  
 223  const (
 224  	notFloatKind floatKind = iota
 225  	floatKind32
 226  	floatKind64
 227  )
 228  
 229  type Parameter struct {
 230  	InRegister bool
 231  	IsPointer  bool
 232  	IsFloat    floatKind
 233  	Reg        Register
 234  	Mem        uint32
 235  	Type       reflect.Type
 236  }
 237  
 238  func mkIReg(vt reflect.Type, reg Register64) (p Parameter) {
 239  	p.Reg = reg
 240  	p.Type = vt
 241  	p.InRegister = true
 242  	p.IsPointer = isPointer(vt)
 243  	return
 244  }
 245  
 246  func isFloat(vt reflect.Type) floatKind {
 247  	switch vt.Kind() {
 248  	case reflect.Float32:
 249  		return floatKind32
 250  	case reflect.Float64:
 251  		return floatKind64
 252  	default:
 253  		return notFloatKind
 254  	}
 255  }
 256  
 257  func mkXReg(vt reflect.Type, reg XMMRegister) (p Parameter) {
 258  	p.Reg = reg
 259  	p.Type = vt
 260  	p.InRegister = true
 261  	p.IsFloat = isFloat(vt)
 262  	return
 263  }
 264  
 265  func mkStack(vt reflect.Type, mem uint32) (p Parameter) {
 266  	p.Mem = mem
 267  	p.Type = vt
 268  	p.InRegister = false
 269  	p.IsPointer = isPointer(vt)
 270  	p.IsFloat = isFloat(vt)
 271  	return
 272  }
 273  
 274  func (self Parameter) String() string {
 275  	if self.InRegister {
 276  		return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
 277  	} else {
 278  		return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
 279  	}
 280  }
 281  
 282  func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
 283  	p := DefaultArch.CreateProgram()
 284  
 285  	stack := CreateLabel("_stack_grow")
 286  	entry := CreateLabel("_entry")
 287  	p.Link(entry)
 288  	fr.emitStackCheck(p, stack, maxStack)
 289  	fr.emitPrologue(p)
 290  	fr.emitReserveRegs(p)
 291  	fr.emitSpillPtrs(p)
 292  	fr.emitExchangeArgs(p)
 293  	fr.emitCallC(p, addr)
 294  	fr.emitExchangeRets(p)
 295  	fr.emitRestoreRegs(p)
 296  	fr.emitEpilogue(p)
 297  	p.Link(stack)
 298  	fr.emitGrowStack(p, entry)
 299  
 300  	return p.Assemble(0)
 301  }
 302