ssa_exports.mx raw
1 package main
2
3 import (
4 "bytes"
5 "runtime"
6 "unsafe"
7 )
8
9 var ssaProgHandles []*SSAProgram
10 var ssaPkgHandles []*SSAPackage
11
12 func allocSSAProgHandle(p *SSAProgram) int32 {
13 for i, h := range ssaProgHandles {
14 if h == nil {
15 ssaProgHandles[i] = p
16 return int32(i)
17 }
18 }
19 ssaProgHandles = append(ssaProgHandles, p)
20 return int32(len(ssaProgHandles) - 1)
21 }
22
23 func getSSAProg(h int32) *SSAProgram {
24 if h < 0 || int(h) >= len(ssaProgHandles) {
25 return nil
26 }
27 return ssaProgHandles[h]
28 }
29
30 func allocSSAPkgHandle(p *SSAPackage) int32 {
31 for i, h := range ssaPkgHandles {
32 if h == nil {
33 ssaPkgHandles[i] = p
34 return int32(i)
35 }
36 }
37 ssaPkgHandles = append(ssaPkgHandles, p)
38 return int32(len(ssaPkgHandles) - 1)
39 }
40
41 func getSSAPkg(h int32) *SSAPackage {
42 if h < 0 || int(h) >= len(ssaPkgHandles) {
43 return nil
44 }
45 return ssaPkgHandles[h]
46 }
47
48 func ssaCopyOut(dst unsafe.Pointer, cap int32, src string) int32 {
49 n := int32(len(src))
50 if n > cap {
51 n = cap
52 }
53 if n > 0 {
54 buf := unsafe.Slice((*byte)(dst), n)
55 copy(buf, src[:n])
56 }
57 return n
58 }
59
60 //export moxie_ssa_new_program
61 func moxie_ssa_new_program() int32 {
62 runtime.InitCShared()
63 prog := NewSSAProgram()
64 return allocSSAProgHandle(prog)
65 }
66
67 //export moxie_ssa_build_package
68 func moxie_ssa_build_package(progH int32, srcPtr unsafe.Pointer, srcLen int32, namePtr unsafe.Pointer, nameLen int32) int32 {
69 runtime.InitCShared()
70 initUniverse()
71 InitKeywords()
72 prog := getSSAProg(progH)
73 if prog == nil {
74 return -1
75 }
76 src := unsafe.Slice((*byte)(srcPtr), srcLen)
77 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
78 r := bytes.NewReader(src)
79 f, err := Parse(NewFileBase(name), r, nil, nil, 0)
80 if err != nil || f == nil {
81 return -2
82 }
83
84 pkg := NewTCPackage(name, packageName([]*File{f}))
85 scope := pkg.Scope()
86 for _, d := range f.DeclList {
87 switch d := d.(type) {
88 case *VarDecl:
89 for _, n := range d.NameList {
90 scope.Insert(NewTCVar(pkg, n.Value, nil))
91 }
92 case *FuncDecl:
93 if d.Recv == nil && d.Name.Value != "init" {
94 scope.Insert(NewTCFunc(pkg, d.Name.Value, nil))
95 }
96 case *TypeDecl:
97 scope.Insert(NewTypeName(pkg, d.Name.Value, nil))
98 case *ConstDecl:
99 for _, n := range d.NameList {
100 scope.Insert(NewTCConst(pkg, n.Value, nil, nil))
101 }
102 }
103 }
104
105 for _, d := range f.DeclList {
106 switch d := d.(type) {
107 case *VarDecl:
108 typ := tcResolveNameInline(d.Type)
109 for _, n := range d.NameList {
110 obj := scope.Lookup(n.Value)
111 if obj != nil {
112 if v, ok := obj.(*TCVar); ok {
113 v.typ = typ
114 }
115 }
116 }
117 case *FuncDecl:
118 if d.Recv == nil && d.Name.Value != "init" {
119 sig := tcResolveFuncInline(d.Type)
120 obj := scope.Lookup(d.Name.Value)
121 if obj != nil {
122 if fn, ok := obj.(*TCFunc); ok && sig != nil {
123 fn.typ = sig
124 }
125 }
126 }
127 case *TypeDecl:
128 typ := tcResolveNameInline(d.Type)
129 obj := scope.Lookup(d.Name.Value)
130 if obj != nil {
131 if tn, ok := obj.(*TypeName); ok {
132 tn.typ = typ
133 }
134 }
135 }
136 }
137
138 ssaPkg := prog.CreatePackage(pkg, []*File{f}, nil)
139 return allocSSAPkgHandle(ssaPkg)
140 }
141
142 //export moxie_ssa_pkg_member_count
143 func moxie_ssa_pkg_member_count(h int32) int32 {
144 runtime.InitCShared()
145 p := getSSAPkg(h)
146 if p == nil {
147 return 0
148 }
149 return int32(len(p.Members))
150 }
151
152 var cachedSSAMemberNames [][]string
153
154 func getSSAMemberNames(h int32) []string {
155 for int(h) >= len(cachedSSAMemberNames) {
156 cachedSSAMemberNames = append(cachedSSAMemberNames, nil)
157 }
158 if cachedSSAMemberNames[h] == nil {
159 p := getSSAPkg(h)
160 if p == nil {
161 return nil
162 }
163 var names []string
164 for name := range p.Members {
165 names = append(names, name)
166 }
167 cachedSSAMemberNames[h] = names
168 }
169 return cachedSSAMemberNames[h]
170 }
171
172 //export moxie_ssa_pkg_member_name
173 func moxie_ssa_pkg_member_name(h int32, idx int32, out unsafe.Pointer, cap int32) int32 {
174 runtime.InitCShared()
175 names := getSSAMemberNames(h)
176 if idx < 0 || int(idx) >= len(names) {
177 return 0
178 }
179 return ssaCopyOut(out, cap, names[idx])
180 }
181
182 //export moxie_ssa_member_kind
183 func moxie_ssa_member_kind(pkgH int32, namePtr unsafe.Pointer, nameLen int32) int32 {
184 runtime.InitCShared()
185 p := getSSAPkg(pkgH)
186 if p == nil {
187 return 0
188 }
189 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
190 m := p.Members[name]
191 if m == nil {
192 return 0
193 }
194 switch m.(type) {
195 case *SSAFunction:
196 return 1
197 case *SSAGlobal:
198 return 2
199 case *SSAType_:
200 return 3
201 case *SSANamedConst:
202 return 4
203 }
204 return 0
205 }
206
207 //export moxie_ssa_func_block_count
208 func moxie_ssa_func_block_count(pkgH int32, namePtr unsafe.Pointer, nameLen int32) int32 {
209 runtime.InitCShared()
210 p := getSSAPkg(pkgH)
211 if p == nil {
212 return -1
213 }
214 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
215 fn := p.Func(name)
216 if fn == nil {
217 return -1
218 }
219 return int32(len(fn.Blocks))
220 }
221
222 //export moxie_ssa_func_param_count
223 func moxie_ssa_func_param_count(pkgH int32, namePtr unsafe.Pointer, nameLen int32) int32 {
224 runtime.InitCShared()
225 p := getSSAPkg(pkgH)
226 if p == nil {
227 return -1
228 }
229 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
230 fn := p.Func(name)
231 if fn == nil {
232 return -1
233 }
234 return int32(len(fn.Params))
235 }
236
237 //export moxie_ssa_func_local_count
238 func moxie_ssa_func_local_count(pkgH int32, namePtr unsafe.Pointer, nameLen int32) int32 {
239 runtime.InitCShared()
240 p := getSSAPkg(pkgH)
241 if p == nil {
242 return -1
243 }
244 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
245 fn := p.Func(name)
246 if fn == nil {
247 return -1
248 }
249 return int32(len(fn.Locals))
250 }
251
252 //export moxie_ssa_block_instr_count
253 func moxie_ssa_block_instr_count(pkgH int32, namePtr unsafe.Pointer, nameLen int32, blockIdx int32) int32 {
254 runtime.InitCShared()
255 p := getSSAPkg(pkgH)
256 if p == nil {
257 return -1
258 }
259 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
260 fn := p.Func(name)
261 if fn == nil || blockIdx < 0 || int(blockIdx) >= len(fn.Blocks) {
262 return -1
263 }
264 return int32(len(fn.Blocks[blockIdx].Instrs))
265 }
266
267 //export moxie_ssa_instr_string
268 func moxie_ssa_instr_string(pkgH int32, namePtr unsafe.Pointer, nameLen int32, blockIdx int32, instrIdx int32, out unsafe.Pointer, cap int32) int32 {
269 runtime.InitCShared()
270 p := getSSAPkg(pkgH)
271 if p == nil {
272 return 0
273 }
274 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
275 fn := p.Func(name)
276 if fn == nil || blockIdx < 0 || int(blockIdx) >= len(fn.Blocks) {
277 return 0
278 }
279 blk := fn.Blocks[blockIdx]
280 if instrIdx < 0 || int(instrIdx) >= len(blk.Instrs) {
281 return 0
282 }
283 return ssaCopyOut(out, cap, blk.Instrs[instrIdx].InstrString())
284 }
285
286 //export moxie_ssa_func_type
287 func moxie_ssa_func_type(pkgH int32, namePtr unsafe.Pointer, nameLen int32, out unsafe.Pointer, cap int32) int32 {
288 runtime.InitCShared()
289 p := getSSAPkg(pkgH)
290 if p == nil {
291 return 0
292 }
293 name := string(unsafe.Slice((*byte)(namePtr), nameLen))
294 fn := p.Func(name)
295 if fn == nil || fn.Signature == nil {
296 return 0
297 }
298 return ssaCopyOut(out, cap, fn.Signature.String())
299 }
300
301 //export moxie_ssa_free_pkg
302 func moxie_ssa_free_pkg(h int32) {
303 runtime.InitCShared()
304 if h >= 0 && int(h) < len(ssaPkgHandles) {
305 ssaPkgHandles[h] = nil
306 }
307 if h >= 0 && int(h) < len(cachedSSAMemberNames) {
308 cachedSSAMemberNames[h] = nil
309 }
310 }
311
312 //export moxie_ssa_free_prog
313 func moxie_ssa_free_prog(h int32) {
314 runtime.InitCShared()
315 if h >= 0 && int(h) < len(ssaProgHandles) {
316 ssaProgHandles[h] = nil
317 }
318 }
319
320 func tcResolveNameInline(e Expr) Type {
321 if e == nil {
322 return nil
323 }
324 switch e := e.(type) {
325 case *Name:
326 _, obj := Universe.LookupParent(e.Value)
327 if obj != nil {
328 if tn, ok := obj.(*TypeName); ok {
329 return tn.typ
330 }
331 }
332 case *Operation:
333 if e.Y == nil && e.Op == Mul {
334 base := tcResolveNameInline(e.X)
335 if base != nil {
336 return NewPointer(base)
337 }
338 }
339 case *SliceType:
340 elem := tcResolveNameInline(e.Elem)
341 if elem != nil {
342 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
343 return Typ[TCString]
344 }
345 return NewSlice(elem)
346 }
347 case *ArrayType:
348 elem := tcResolveNameInline(e.Elem)
349 if elem != nil {
350 return NewArray(elem, -1)
351 }
352 case *MapType:
353 key := tcResolveNameInline(e.Key)
354 val := tcResolveNameInline(e.Value)
355 if key != nil && val != nil {
356 return NewTCMap(key, val)
357 }
358 case *StructType:
359 var fields []*TCVar
360 var tags []string
361 for i, field := range e.FieldList {
362 typ := tcResolveNameInline(field.Type)
363 fname := ""
364 if field.Name != nil {
365 fname = field.Name.Value
366 }
367 fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
368 tag := ""
369 if i < len(e.TagList) && e.TagList[i] != nil {
370 tag = e.TagList[i].Value
371 }
372 tags = append(tags, tag)
373 }
374 return NewTCStruct(fields, tags)
375 case *FuncType:
376 return tcResolveFuncInline(e)
377 case *DotsType:
378 elem := tcResolveNameInline(e.Elem)
379 if elem != nil {
380 if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
381 return Typ[TCString]
382 }
383 return NewSlice(elem)
384 }
385 }
386 return nil
387 }
388
389 func tcResolveFuncInline(ft *FuncType) *Signature {
390 if ft == nil {
391 return nil
392 }
393 var params []*TCVar
394 for _, p := range ft.ParamList {
395 typ := tcResolveNameInline(p.Type)
396 pname := ""
397 if p.Name != nil {
398 pname = p.Name.Value
399 }
400 params = append(params, NewTCVar(nil, pname, typ))
401 }
402 var results []*TCVar
403 for _, r := range ft.ResultList {
404 typ := tcResolveNameInline(r.Type)
405 rname := ""
406 if r.Name != nil {
407 rname = r.Name.Value
408 }
409 results = append(results, NewTCVar(nil, rname, typ))
410 }
411 variadic := false
412 if len(ft.ParamList) > 0 {
413 if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*DotsType); ok {
414 variadic = true
415 }
416 }
417 var pTuple *Tuple
418 if len(params) > 0 {
419 pTuple = NewTuple(params...)
420 }
421 var rTuple *Tuple
422 if len(results) > 0 {
423 rTuple = NewTuple(results...)
424 }
425 return NewSignature(nil, pTuple, rTuple, variadic)
426 }
427
428 func main() {}
429