summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/loader/internal/abi/abi_amd64.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bytedance/sonic/loader/internal/abi/abi_amd64.go')
-rw-r--r--vendor/github.com/bytedance/sonic/loader/internal/abi/abi_amd64.go282
1 files changed, 282 insertions, 0 deletions
diff --git a/vendor/github.com/bytedance/sonic/loader/internal/abi/abi_amd64.go b/vendor/github.com/bytedance/sonic/loader/internal/abi/abi_amd64.go
new file mode 100644
index 000000000..c2b45a8e1
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/internal/abi/abi_amd64.go
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2022 ByteDance Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package abi
+
+import (
+ `fmt`
+ `reflect`
+ `unsafe`
+
+ . `github.com/cloudwego/iasm/x86_64`
+)
+
+const (
+ PtrSize = 8 // pointer size
+ PtrAlign = 8 // pointer alignment
+)
+
+var iregOrderC = []Register{
+ RDI,
+ RSI,
+ RDX,
+ RCX,
+ R8,
+ R9,
+}
+
+var xregOrderC = []Register{
+ XMM0,
+ XMM1,
+ XMM2,
+ XMM3,
+ XMM4,
+ XMM5,
+ XMM6,
+ XMM7,
+}
+
+var (
+ intType = reflect.TypeOf(0)
+ ptrType = reflect.TypeOf(unsafe.Pointer(nil))
+)
+
+func (self *Frame) argv(i int) *MemoryOperand {
+ return Ptr(RSP, int32(self.Prev() + self.desc.Args[i].Mem))
+}
+
+// spillv is used for growstack spill registers
+func (self *Frame) spillv(i int) *MemoryOperand {
+ // remain one slot for caller return pc
+ return Ptr(RSP, PtrSize + int32(self.desc.Args[i].Mem))
+}
+
+func (self *Frame) retv(i int) *MemoryOperand {
+ return Ptr(RSP, int32(self.Prev() + self.desc.Rets[i].Mem))
+}
+
+func (self *Frame) resv(i int) *MemoryOperand {
+ return Ptr(RSP, int32(self.Offs() - uint32((i+1) * PtrSize)))
+}
+
+func (self *Frame) emitGrowStack(p *Program, entry *Label) {
+ // spill all register arguments
+ for i, v := range self.desc.Args {
+ if v.InRegister {
+ if v.IsFloat == floatKind64 {
+ p.MOVSD(v.Reg, self.spillv(i))
+ } else if v.IsFloat == floatKind32 {
+ p.MOVSS(v.Reg, self.spillv(i))
+ }else {
+ p.MOVQ(v.Reg, self.spillv(i))
+ }
+ }
+ }
+
+ // call runtime.morestack_noctxt
+ p.MOVQ(F_morestack_noctxt, R12)
+ p.CALLQ(R12)
+ // load all register arguments
+ for i, v := range self.desc.Args {
+ if v.InRegister {
+ if v.IsFloat == floatKind64 {
+ p.MOVSD(self.spillv(i), v.Reg)
+ } else if v.IsFloat == floatKind32 {
+ p.MOVSS(self.spillv(i), v.Reg)
+ }else {
+ p.MOVQ(self.spillv(i), v.Reg)
+ }
+ }
+ }
+
+ // jump back to the function entry
+ p.JMP(entry)
+}
+
+func (self *Frame) GrowStackTextSize() uint32 {
+ p := DefaultArch.CreateProgram()
+ // spill all register arguments
+ for i, v := range self.desc.Args {
+ if v.InRegister {
+ if v.IsFloat == floatKind64 {
+ p.MOVSD(v.Reg, self.spillv(i))
+ } else if v.IsFloat == floatKind32 {
+ p.MOVSS(v.Reg, self.spillv(i))
+ }else {
+ p.MOVQ(v.Reg, self.spillv(i))
+ }
+ }
+ }
+
+ // call runtime.morestack_noctxt
+ p.MOVQ(F_morestack_noctxt, R12)
+ p.CALLQ(R12)
+ // load all register arguments
+ for i, v := range self.desc.Args {
+ if v.InRegister {
+ if v.IsFloat == floatKind64 {
+ p.MOVSD(self.spillv(i), v.Reg)
+ } else if v.IsFloat == floatKind32 {
+ p.MOVSS(self.spillv(i), v.Reg)
+ } else {
+ p.MOVQ(self.spillv(i), v.Reg)
+ }
+ }
+ }
+
+ // jump back to the function entry
+ l := CreateLabel("")
+ p.Link(l)
+ p.JMP(l)
+
+ return uint32(len(p.Assemble(0)))
+}
+
+func (self *Frame) emitPrologue(p *Program) {
+ p.SUBQ(self.Size(), RSP)
+ p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
+ p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
+}
+
+func (self *Frame) emitEpilogue(p *Program) {
+ p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
+ p.ADDQ(self.Size(), RSP)
+ p.RET()
+}
+
+func (self *Frame) emitReserveRegs(p *Program) {
+ // spill reserved registers
+ for i, r := range ReservedRegs(self.ccall) {
+ switch r.(type) {
+ case Register64:
+ p.MOVQ(r, self.resv(i))
+ case XMMRegister:
+ p.MOVSD(r, self.resv(i))
+ default:
+ panic(fmt.Sprintf("unsupported register type %t to reserve", r))
+ }
+ }
+}
+
+func (self *Frame) emitSpillPtrs(p *Program) {
+ // spill pointer argument registers
+ for i, r := range self.desc.Args {
+ if r.InRegister && r.IsPointer {
+ p.MOVQ(r.Reg, self.argv(i))
+ }
+ }
+}
+
+func (self *Frame) emitClearPtrs(p *Program) {
+ // spill pointer argument registers
+ for i, r := range self.desc.Args {
+ if r.InRegister && r.IsPointer {
+ p.MOVQ(int64(0), self.argv(i))
+ }
+ }
+}
+
+func (self *Frame) emitCallC(p *Program, addr uintptr) {
+ p.MOVQ(addr, RAX)
+ p.CALLQ(RAX)
+}
+
+type floatKind uint8
+
+const (
+ notFloatKind floatKind = iota
+ floatKind32
+ floatKind64
+)
+
+type Parameter struct {
+ InRegister bool
+ IsPointer bool
+ IsFloat floatKind
+ Reg Register
+ Mem uint32
+ Type reflect.Type
+}
+
+func mkIReg(vt reflect.Type, reg Register64) (p Parameter) {
+ p.Reg = reg
+ p.Type = vt
+ p.InRegister = true
+ p.IsPointer = isPointer(vt)
+ return
+}
+
+func isFloat(vt reflect.Type) floatKind {
+ switch vt.Kind() {
+ case reflect.Float32:
+ return floatKind32
+ case reflect.Float64:
+ return floatKind64
+ default:
+ return notFloatKind
+ }
+}
+
+func mkXReg(vt reflect.Type, reg XMMRegister) (p Parameter) {
+ p.Reg = reg
+ p.Type = vt
+ p.InRegister = true
+ p.IsFloat = isFloat(vt)
+ return
+}
+
+func mkStack(vt reflect.Type, mem uint32) (p Parameter) {
+ p.Mem = mem
+ p.Type = vt
+ p.InRegister = false
+ p.IsPointer = isPointer(vt)
+ p.IsFloat = isFloat(vt)
+ return
+}
+
+func (self Parameter) String() string {
+ if self.InRegister {
+ return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
+ } else {
+ return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
+ }
+}
+
+func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
+ p := DefaultArch.CreateProgram()
+
+ stack := CreateLabel("_stack_grow")
+ entry := CreateLabel("_entry")
+ p.Link(entry)
+ fr.emitStackCheck(p, stack, maxStack)
+ fr.emitPrologue(p)
+ fr.emitReserveRegs(p)
+ fr.emitSpillPtrs(p)
+ fr.emitExchangeArgs(p)
+ fr.emitCallC(p, addr)
+ fr.emitExchangeRets(p)
+ fr.emitRestoreRegs(p)
+ fr.emitEpilogue(p)
+ p.Link(stack)
+ fr.emitGrowStack(p, entry)
+
+ return p.Assemble(0)
+}
+
+
+func (self *Frame) emitDebug(p *Program) {
+ p.INT(3)
+} \ No newline at end of file