podman

Форк
0
269 строк · 7.2 Кб
1
/*
2
 * Copyright 2021 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 jit
18

19
import (
20
    `encoding/binary`
21
    `strconv`
22
    `strings`
23
    `sync`
24

25
    `github.com/bytedance/sonic/loader`
26
    `github.com/bytedance/sonic/internal/rt`
27
    `github.com/twitchyliquid64/golang-asm/obj`
28
    `github.com/twitchyliquid64/golang-asm/obj/x86`
29
)
30

31
const (
32
    _LB_jump_pc = "_jump_pc_"
33
)
34

35
type BaseAssembler struct {
36
    i        int
37
    f        func()
38
    c        []byte
39
    o        sync.Once
40
    pb       *Backend
41
    xrefs    map[string][]*obj.Prog
42
    labels   map[string]*obj.Prog
43
    pendings map[string][]*obj.Prog
44
}
45

46
/** Instruction Encoders **/
47

48
var _NOPS = [][16]byte {
49
    {0x90},                                                     // NOP
50
    {0x66, 0x90},                                               // 66 NOP
51
    {0x0f, 0x1f, 0x00},                                         // NOP DWORD ptr [EAX]
52
    {0x0f, 0x1f, 0x40, 0x00},                                   // NOP DWORD ptr [EAX + 00H]
53
    {0x0f, 0x1f, 0x44, 0x00, 0x00},                             // NOP DWORD ptr [EAX + EAX*1 + 00H]
54
    {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00},                       // 66 NOP DWORD ptr [EAX + EAX*1 + 00H]
55
    {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00},                 // NOP DWORD ptr [EAX + 00000000H]
56
    {0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},           // NOP DWORD ptr [EAX + EAX*1 + 00000000H]
57
    {0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},     // 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H]
58
}
59

60
func (self *BaseAssembler) NOP() *obj.Prog {
61
    p := self.pb.New()
62
    p.As = obj.ANOP
63
    self.pb.Append(p)
64
    return p
65
}
66

67
func (self *BaseAssembler) NOPn(n int) {
68
    for i := len(_NOPS); i > 0 && n > 0; i-- {
69
        for ; n >= i; n -= i {
70
            self.Byte(_NOPS[i - 1][:i]...)
71
        }
72
    }
73
}
74

75
func (self *BaseAssembler) Byte(v ...byte) {
76
    for ; len(v) >= 8; v = v[8:] { self.From("QUAD", Imm(rt.Get64(v))) }
77
    for ; len(v) >= 4; v = v[4:] { self.From("LONG", Imm(int64(rt.Get32(v)))) }
78
    for ; len(v) >= 2; v = v[2:] { self.From("WORD", Imm(int64(rt.Get16(v)))) }
79
    for ; len(v) >= 1; v = v[1:] { self.From("BYTE", Imm(int64(v[0]))) }
80
}
81

82
func (self *BaseAssembler) Mark(pc int) {
83
    self.i++
84
    self.Link(_LB_jump_pc + strconv.Itoa(pc))
85
}
86

87
func (self *BaseAssembler) Link(to string) {
88
    var p *obj.Prog
89
    var v []*obj.Prog
90

91
    /* placeholder substitution */
92
    if strings.Contains(to, "{n}") {
93
        to = strings.ReplaceAll(to, "{n}", strconv.Itoa(self.i))
94
    }
95

96
    /* check for duplications */
97
    if _, ok := self.labels[to]; ok {
98
        panic("label " + to + " has already been linked")
99
    }
100

101
    /* get the pending links */
102
    p = self.NOP()
103
    v = self.pendings[to]
104

105
    /* patch all the pending jumps */
106
    for _, q := range v {
107
        q.To.Val = p
108
    }
109

110
    /* mark the label as resolved */
111
    self.labels[to] = p
112
    delete(self.pendings, to)
113
}
114

115
func (self *BaseAssembler) Xref(pc int, d int64) {
116
    self.Sref(_LB_jump_pc + strconv.Itoa(pc), d)
117
}
118

119
func (self *BaseAssembler) Sref(to string, d int64) {
120
    p := self.pb.New()
121
    p.As = x86.ALONG
122
    p.From = Imm(-d)
123

124
    /* placeholder substitution */
125
    if strings.Contains(to, "{n}") {
126
        to = strings.ReplaceAll(to, "{n}", strconv.Itoa(self.i))
127
    }
128

129
    /* record the patch point */
130
    self.pb.Append(p)
131
    self.xrefs[to] = append(self.xrefs[to], p)
132
}
133

134
func (self *BaseAssembler) Xjmp(op string, to int) {
135
    self.Sjmp(op, _LB_jump_pc + strconv.Itoa(to))
136
}
137

138
func (self *BaseAssembler) Sjmp(op string, to string) {
139
    p := self.pb.New()
140
    p.As = As(op)
141

142
    /* placeholder substitution */
143
    if strings.Contains(to, "{n}") {
144
        to = strings.ReplaceAll(to, "{n}", strconv.Itoa(self.i))
145
    }
146

147
    /* check for backward jumps */
148
    if v, ok := self.labels[to]; ok {
149
        p.To.Val = v
150
    } else {
151
        self.pendings[to] = append(self.pendings[to], p)
152
    }
153

154
    /* mark as a branch, and add to instruction buffer */
155
    p.To.Type = obj.TYPE_BRANCH
156
    self.pb.Append(p)
157
}
158

159
func (self *BaseAssembler) Rjmp(op string, to obj.Addr) {
160
    p := self.pb.New()
161
    p.To = to
162
    p.As = As(op)
163
    self.pb.Append(p)
164
}
165

166
func (self *BaseAssembler) From(op string, val obj.Addr) {
167
    p := self.pb.New()
168
    p.As = As(op)
169
    p.From = val
170
    self.pb.Append(p)
171
}
172

173
func (self *BaseAssembler) Emit(op string, args ...obj.Addr) {
174
    p := self.pb.New()
175
    p.As = As(op)
176
    self.assignOperands(p, args)
177
    self.pb.Append(p)
178
}
179

180
func (self *BaseAssembler) assignOperands(p *obj.Prog, args []obj.Addr) {
181
    switch len(args) {
182
        case 0  :
183
        case 1  : p.To                     = args[0]
184
        case 2  : p.To, p.From             = args[1], args[0]
185
        case 3  : p.To, p.From, p.RestArgs = args[2], args[0], args[1:2]
186
        case 4  : p.To, p.From, p.RestArgs = args[2], args[3], args[:2]
187
        default : panic("invalid operands")
188
    }
189
}
190

191
/** Assembler Helpers **/
192

193
func (self *BaseAssembler) Size() int {
194
    self.build()
195
    return len(self.c)
196
}
197

198
func (self *BaseAssembler) Init(f func()) {
199
    self.i = 0
200
    self.f = f
201
    self.c = nil
202
    self.o = sync.Once{}
203
}
204

205
var jitLoader = loader.Loader{
206
    Name: "sonic.jit.",
207
    File: "github.com/bytedance/sonic/jit.go",
208
    Options: loader.Options{
209
        NoPreempt: true,
210
    },
211
}
212

213
func (self *BaseAssembler) Load(name string, frameSize int, argSize int, argStackmap []bool, localStackmap []bool) loader.Function {
214
    self.build()
215
    return jitLoader.LoadOne(self.c, name, frameSize, argSize, argStackmap, localStackmap)
216
}
217

218
/** Assembler Stages **/
219

220
func (self *BaseAssembler) init() {
221
    self.pb       = newBackend("amd64")
222
    self.xrefs    = map[string][]*obj.Prog{}
223
    self.labels   = map[string]*obj.Prog{}
224
    self.pendings = map[string][]*obj.Prog{}
225
}
226

227
func (self *BaseAssembler) build() {
228
    self.o.Do(func() {
229
        self.init()
230
        self.f()
231
        self.validate()
232
        self.assemble()
233
        self.resolve()
234
        self.release()
235
    })
236
}
237

238
func (self *BaseAssembler) release() {
239
    self.pb.Release()
240
    self.pb = nil
241
    self.xrefs = nil
242
    self.labels = nil
243
    self.pendings = nil
244
}
245

246
func (self *BaseAssembler) resolve() {
247
    for s, v := range self.xrefs {
248
        for _, prog := range v {
249
            if prog.As != x86.ALONG {
250
                panic("invalid RIP relative reference")
251
            } else if p, ok := self.labels[s]; !ok {
252
                panic("links are not fully resolved: " + s)
253
            } else {
254
                off := prog.From.Offset + p.Pc - prog.Pc
255
                binary.LittleEndian.PutUint32(self.c[prog.Pc:], uint32(off))
256
            }
257
        }
258
    }
259
}
260

261
func (self *BaseAssembler) validate() {
262
    for key := range self.pendings {
263
        panic("links are not fully resolved: " + key)
264
    }
265
}
266

267
func (self *BaseAssembler) assemble() {
268
    self.c = self.pb.Assemble()
269
}
270

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.