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