Merge pull request #53 from xushiwei/q

cl: _testcgo/strlen
This commit is contained in:
xushiwei
2024-04-26 03:28:08 +08:00
committed by GitHub
20 changed files with 262 additions and 100 deletions

View File

@@ -35,13 +35,10 @@ func main() {
dir, _ := filepath.Split(inFile) dir, _ := filepath.Split(inFile)
outFile := dir + "out.ll" outFile := dir + "out.ll"
pkgPath := ""
if len(os.Args) == 3 {
pkgPath = os.Args[2]
} else {
pkgPath = llgen.PkgPath(dir)
}
llgen.Init() llgen.Init()
llgen.Do(pkgPath, inFile, outFile) if len(os.Args) >= 3 {
llgen.Do(os.Args[2], inFile, outFile)
} else {
llgen.DoFile(inFile, outFile)
}
} }

17
cl/_testcgo/strlen/in.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "C"
import _ "unsafe"
//go:linkname printf printf
func printf(format *int8, __llgo_va_list ...any)
//go:linkname strlen strlen
func strlen(str *int8) C.int
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
func main() {
sfmt := &format[0]
printf(sfmt, strlen(sfmt))
}

41
cl/_testcgo/strlen/out.ll Normal file
View File

@@ -0,0 +1,41 @@
; ModuleID = 'main'
source_filename = "main"
@main._Cgo_always_false = global ptr null
@main.format = global ptr null
@"main.init$guard" = global ptr null
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
store i8 72, ptr @main.format, align 1
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @main.init()
%0 = call i32 @strlen(ptr @main.format)
call void (ptr, ...) @printf(ptr @main.format, i32 %0)
ret void
}
declare void @printf(ptr, ...)
declare i32 @strlen(ptr)

View File

@@ -3,6 +3,18 @@ source_filename = "apkg"
@"apkg.init$guard" = global ptr null @"apkg.init$guard" = global ptr null
define double @apkg.Max(double %0, double %1) {
_llgo_0:
%2 = fcmp ogt double %0, %1
br i1 %2, label %_llgo_1, label %_llgo_2
_llgo_1: ; preds = %_llgo_0
ret double %0
_llgo_2: ; preds = %_llgo_0
ret double %1
}
define void @apkg.init() { define void @apkg.init() {
_llgo_0: _llgo_0:
%0 = load i1, ptr @"apkg.init$guard", align 1 %0 = load i1, ptr @"apkg.init$guard", align 1
@@ -15,15 +27,3 @@ _llgo_1: ; preds = %_llgo_0
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
define double @apkg.Max(double %0, double %1) {
_llgo_0:
%2 = fcmp ogt double %0, %1
br i1 %2, label %_llgo_1, label %_llgo_2
_llgo_1: ; preds = %_llgo_0
ret double %0
_llgo_2: ; preds = %_llgo_0
ret double %1
}

View File

@@ -16,6 +16,13 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
define void @main() {
_llgo_0:
call void @main.init()
%0 = call i64 @main.max(i64 1, i64 2)
ret void
}
define i64 @main.max(i64 %0, i64 %1) { define i64 @main.max(i64 %0, i64 %1) {
_llgo_0: _llgo_0:
%2 = icmp sgt i64 %0, %1 %2 = icmp sgt i64 %0, %1
@@ -27,10 +34,3 @@ _llgo_1: ; preds = %_llgo_0
_llgo_2: ; preds = %_llgo_0 _llgo_2: ; preds = %_llgo_0
ret i64 %1 ret i64 %1
} }
define void @main() {
_llgo_0:
call void @main.init()
%0 = call i64 @main.max(i64 1, i64 2)
ret void
}

View File

@@ -1,8 +1,8 @@
; ModuleID = 'main' ; ModuleID = 'main'
source_filename = "main" source_filename = "main"
@"main.init$guard" = global ptr null
@main.hello = global ptr null @main.hello = global ptr null
@"main.init$guard" = global ptr null
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:

View File

@@ -1,8 +1,21 @@
; ModuleID = 'main' ; ModuleID = 'main'
source_filename = "main" source_filename = "main"
@"main.init$guard" = global ptr null
@main.format = global ptr null @main.format = global ptr null
@"main.init$guard" = global ptr null
define i64 @"(T).Add"(i64 %0, i64 %1) {
_llgo_0:
%2 = add i64 %0, %1
ret i64 %2
}
define i64 @"(*T).Add"(ptr %0, i64 %1) {
_llgo_0:
%2 = load i64, ptr %0, align 4
%3 = call i64 @"(T).Add"(i64 %2, i64 %1)
ret i64 %3
}
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:
@@ -27,25 +40,12 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
define i64 @"(main.T).Add"(i64 %0, i64 %1) {
_llgo_0:
%2 = add i64 %0, %1
ret i64 %2
}
define i64 @"(*main.T).Add"(ptr %0, i64 %1) {
_llgo_0:
%2 = load i64, ptr %0, align 4
%3 = call i64 @"(main.T).Add"(i64 %2, i64 %1)
ret i64 %3
}
declare void @printf(ptr, ...)
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @main.init() call void @main.init()
%0 = call i64 @"(main.T).Add"(i64 1, i64 2) %0 = call i64 @"(T).Add"(i64 1, i64 2)
call void (ptr, ...) @printf(ptr @main.format, i64 %0) call void (ptr, ...) @printf(ptr @main.format, i64 %0)
ret void ret void
} }
declare void @printf(ptr, ...)

View File

@@ -1,8 +1,8 @@
; ModuleID = 'main' ; ModuleID = 'main'
source_filename = "main" source_filename = "main"
@"main.init$guard" = global ptr null
@main.hello = global ptr null @main.hello = global ptr null
@"main.init$guard" = global ptr null
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:
@@ -24,11 +24,11 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
declare void @printf(ptr, ...)
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @main.init() call void @main.init()
call void (ptr, ...) @printf(ptr @main.hello) call void (ptr, ...) @printf(ptr @main.hello)
ret void ret void
} }
declare void @printf(ptr, ...)

View File

@@ -1,8 +1,8 @@
; ModuleID = 'main' ; ModuleID = 'main'
source_filename = "main" source_filename = "main"
@"main.init$guard" = global ptr null
@main.format = global ptr null @main.format = global ptr null
@"main.init$guard" = global ptr null
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:
@@ -27,11 +27,11 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
declare void @printf(ptr, ...)
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @main.init() call void @main.init()
call void (ptr, ...) @printf(ptr @main.format, i64 100) call void (ptr, ...) @printf(ptr @main.format, i64 100)
ret void ret void
} }
declare void @printf(ptr, ...)

View File

@@ -1,8 +1,14 @@
; ModuleID = 'main' ; ModuleID = 'main'
source_filename = "main" source_filename = "main"
@"main.init$guard" = global ptr null
@main.format = global ptr null @main.format = global ptr null
@"main.init$guard" = global ptr null
define void @"(*T).Print"(ptr %0, i64 %1) {
_llgo_0:
call void (ptr, ...) @printf(ptr %0, i64 %1)
ret void
}
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:
@@ -27,17 +33,11 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
declare void @printf(ptr, ...)
define void @"(*main.T).Print"(ptr %0, i64 %1) {
_llgo_0:
call void (ptr, ...) @printf(ptr %0, i64 %1)
ret void
}
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @main.init() call void @main.init()
call void @"(*main.T).Print"(ptr @main.format, i64 100) call void @"(*T).Print"(ptr @main.format, i64 100)
ret void ret void
} }
declare void @printf(ptr, ...)

View File

@@ -1,8 +1,8 @@
; ModuleID = 'main' ; ModuleID = 'main'
source_filename = "main" source_filename = "main"
@"main.init$guard" = global ptr null
@main.a = global ptr null @main.a = global ptr null
@"main.init$guard" = global ptr null
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:

View File

@@ -29,6 +29,7 @@ import (
"github.com/goplus/gogen/packages" "github.com/goplus/gogen/packages"
"github.com/goplus/llgo/cl" "github.com/goplus/llgo/cl"
"github.com/goplus/llgo/internal/llgen"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil" "golang.org/x/tools/go/ssa/ssautil"
@@ -41,7 +42,7 @@ func init() {
llssa.SetDebug(llssa.DbgFlagAll) llssa.SetDebug(llssa.DbgFlagAll)
} }
func FromDir(t *testing.T, sel, relDir string) { func FromDir(t *testing.T, sel, relDir string, byLLGen bool) {
dir, err := os.Getwd() dir, err := os.Getwd()
if err != nil { if err != nil {
t.Fatal("Getwd failed:", err) t.Fatal("Getwd failed:", err)
@@ -57,23 +58,30 @@ func FromDir(t *testing.T, sel, relDir string) {
continue continue
} }
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
testFrom(t, dir+"/"+name, sel) testFrom(t, dir+"/"+name, sel, byLLGen)
}) })
} }
} }
func testFrom(t *testing.T, pkgDir, sel string) { func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) {
if sel != "" && !strings.Contains(pkgDir, sel) { if sel != "" && !strings.Contains(pkgDir, sel) {
return return
} }
log.Println("Parsing", pkgDir) log.Println("Parsing", pkgDir)
in := pkgDir + "/in.go" in := pkgDir + "/in.go"
out := pkgDir + "/out.ll" out := pkgDir + "/out.ll"
expected, err := os.ReadFile(out) b, err := os.ReadFile(out)
if err != nil { if err != nil {
t.Fatal("ReadFile failed:", err) t.Fatal("ReadFile failed:", err)
} }
TestCompileEx(t, nil, in, string(expected)) expected := string(b)
if byLLGen {
if v := llgen.GenFromFile(in); v != expected {
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
}
} else {
TestCompileEx(t, nil, in, expected)
}
} }
func TestCompileEx(t *testing.T, src any, fname, expected string) { func TestCompileEx(t *testing.T, src any, fname, expected string) {

View File

@@ -25,6 +25,7 @@ import (
"log" "log"
"os" "os"
"sort" "sort"
"strings"
llssa "github.com/goplus/llgo/ssa" llssa "github.com/goplus/llgo/ssa"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
@@ -57,7 +58,7 @@ func SetDebug(dbgFlags dbgFlags) {
const ( const (
fnNormal = iota fnNormal = iota
fnHasVArg fnHasVArg
fnUnsafeInit fnIgnore
) )
func funcKind(vfn ssa.Value) int { func funcKind(vfn ssa.Value) int {
@@ -65,8 +66,8 @@ func funcKind(vfn ssa.Value) int {
params := fn.Signature.Params() params := fn.Signature.Params()
n := params.Len() n := params.Len()
if n == 0 { if n == 0 {
if fn.Name() == "init" && fn.Pkg.Pkg.Path() == "unsafe" { if fn.Name() == "init" && ignorePkgInit(fn.Pkg.Pkg.Path()) {
return fnUnsafeInit return fnIgnore
} }
} else { } else {
last := params.At(n - 1) last := params.At(n - 1)
@@ -78,6 +79,32 @@ func funcKind(vfn ssa.Value) int {
return fnNormal return fnNormal
} }
func ignorePkgInit(pkgPath string) bool {
switch pkgPath {
case "unsafe", "syscall", "runtime/cgo":
return true
}
return false
}
func ignoreFunc(name string, fn *ssa.Function) bool {
/* TODO(xsw): confirm this is not needed more
if name == "unsafe.init" {
return true
}
*/
fnName := fn.Name()
if strings.HasPrefix(fnName, "_Cgo_") {
return true
}
const runtime = "runtime"
if strings.HasPrefix(name, runtime) {
left := name[len(runtime):]
return strings.HasPrefix(left, ".cgo") || strings.HasPrefix(left, "/cgo")
}
return false
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type none = struct{} type none = struct{}
@@ -137,14 +164,12 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) { func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
sig := f.Signature sig := f.Signature
name := p.funcName(pkgTypes, f) name := p.funcName(pkgTypes, f)
/* TODO(xsw): confirm this is not needed more
if name == "unsafe.init" {
return
}
*/
if debugInstr { if debugInstr {
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig) log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
} }
if ignoreFunc(name, f) {
return
}
fn := pkg.NewFunc(name, sig) fn := pkg.NewFunc(name, sig)
p.inits = append(p.inits, func() { p.inits = append(p.inits, func() {
p.fn = fn p.fn = fn
@@ -229,7 +254,7 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
call := v.Call call := v.Call
cv := call.Value cv := call.Value
kind := funcKind(cv) kind := funcKind(cv)
if kind == fnUnsafeInit { if kind == fnIgnore {
return return
} }
if debugGoSSA { if debugGoSSA {
@@ -403,17 +428,12 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
val ssa.Member val ssa.Member
} }
// Sort by position, so that the order of the functions in the IR matches members := make([]*namedMember, 0, len(pkg.Members))
// the order of functions in the source file. This is useful for testing,
// for example.
var members []*namedMember
for name, v := range pkg.Members { for name, v := range pkg.Members {
members = append(members, &namedMember{name, v}) members = append(members, &namedMember{name, v})
} }
sort.Slice(members, func(i, j int) bool { sort.Slice(members, func(i, j int) bool {
iPos := members[i].val.Pos() return members[i].name < members[j].name
jPos := members[j].val.Pos()
return iPos < jPos
}) })
pkgProg := pkg.Prog pkgProg := pkg.Prog

View File

@@ -27,8 +27,12 @@ func testCompile(t *testing.T, src, expected string) {
cltest.TestCompileEx(t, src, "foo.go", expected) cltest.TestCompileEx(t, src, "foo.go", expected)
} }
func TestFromTestcgo(t *testing.T) {
cltest.FromDir(t, "", "./_testcgo", true)
}
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {
cltest.FromDir(t, "", "./_testdata") cltest.FromDir(t, "", "./_testdata", false)
} }
func TestVar(t *testing.T) { func TestVar(t *testing.T) {
@@ -38,8 +42,8 @@ var a int
`, `; ModuleID = 'foo' `, `; ModuleID = 'foo'
source_filename = "foo" source_filename = "foo"
@"foo.init$guard" = global ptr null
@foo.a = global ptr null @foo.a = global ptr null
@"foo.init$guard" = global ptr null
define void @foo.init() { define void @foo.init() {
_llgo_0: _llgo_0:
@@ -67,6 +71,11 @@ source_filename = "foo"
@"foo.init$guard" = global ptr null @"foo.init$guard" = global ptr null
define i64 @foo.fn(i64 %0, double %1) {
_llgo_0:
ret i64 1
}
define void @foo.init() { define void @foo.init() {
_llgo_0: _llgo_0:
%0 = load i1, ptr @"foo.init$guard", align 1 %0 = load i1, ptr @"foo.init$guard", align 1
@@ -79,10 +88,5 @@ _llgo_1: ; preds = %_llgo_0
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
define i64 @foo.fn(i64 %0, double %1) {
_llgo_0:
ret i64 1
}
`) `)
} }

View File

@@ -117,13 +117,20 @@ func fullName(pkg *types.Package, name string) string {
} }
// func: pkg.name // func: pkg.name
// method: (pkg.T).name // method: (pkg.T).name, (*pkg.T).name
func funcName(pkg *types.Package, fn *ssa.Function) string { func funcName(pkg *types.Package, fn *ssa.Function) string {
sig := fn.Signature sig := fn.Signature
name := fn.Name()
if recv := sig.Recv(); recv != nil { if recv := sig.Recv(); recv != nil {
return "(" + recv.Type().String() + ")." + fn.Name() var tName string
t := recv.Type()
if tp, ok := t.(*types.Pointer); ok {
t, tName = tp.Elem(), "*"
}
tName += t.(*types.Named).Obj().Name()
return "(" + tName + ")." + name
} }
ret := fullName(pkg, fn.Name()) ret := fullName(pkg, name)
if ret == "main.main" { if ret == "main.main" {
ret = "main" ret = "main"
} }

View File

@@ -133,7 +133,7 @@ func linkMainPkg(pkg *packages.Package, conf *Config, mode Mode) {
args[0] = "-o" args[0] = "-o"
args[1] = app args[1] = app
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) { packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
if p.PkgPath != "unsafe" { // TODO(xsw): remove this special case if p.PkgPath != "unsafe" { // TODO(xsw): maybe can remove this special case
args = append(args, p.ExportFile+".ll") args = append(args, p.ExportFile+".ll")
} }
}) })
@@ -159,7 +159,7 @@ func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode) {
if mode != ModeRun { if mode != ModeRun {
fmt.Fprintln(os.Stderr, pkgPath) fmt.Fprintln(os.Stderr, pkgPath)
} }
if pkgPath == "unsafe" { // TODO(xsw): remove this special case if pkgPath == "unsafe" { // TODO(xsw): maybe can remove this special case
return return
} }
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax) ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)

61
internal/llgen/llgenf.go Normal file
View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* 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 llgen
import (
"os"
"github.com/goplus/llgo/cl"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
llssa "github.com/goplus/llgo/ssa"
)
const (
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
loadImports = loadFiles | packages.NeedImports
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
)
func GenFromFile(inFile string) string {
cfg := &packages.Config{
Mode: loadSyntax,
}
initial, err := packages.Load(cfg, inFile)
check(err)
_, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions)
pkg := initial[0]
ssaPkg := pkgs[0]
ssaPkg.Build()
prog := llssa.NewProgram(nil)
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
check(err)
return ret.String()
}
func DoFile(inFile, outFile string) {
ret := GenFromFile(inFile)
err := os.WriteFile(outFile, []byte(ret), 0644)
check(err)
}

View File

@@ -22,6 +22,10 @@ import (
"github.com/goplus/llgo/cl/cltest" "github.com/goplus/llgo/cl/cltest"
) )
func TestFromTestdata(t *testing.T) { func TestFromTestcgo(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testdata") cltest.FromDir(t, "", "../cl/_testcgo", true)
}
func TestFromTestdata(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testdata", false)
} }

View File

@@ -145,7 +145,8 @@ func (p Function) Param(i int) Expr {
func (p Function) NewBuilder() Builder { func (p Function) NewBuilder() Builder {
prog := p.prog prog := p.prog
b := prog.ctx.NewBuilder() b := prog.ctx.NewBuilder()
b.Finalize() // TODO(xsw): Finalize may cause panic, so comment it.
// b.Finalize()
return &aBuilder{b, p, prog} return &aBuilder{b, p, prog}
} }

View File

@@ -122,7 +122,8 @@ func NewProgram(target *Target) Program {
target = &Target{} target = &Target{}
} }
ctx := llvm.NewContext() ctx := llvm.NewContext()
ctx.Finalize() // TODO(xsw): Finalize may cause panic, so comment it.
// ctx.Finalize()
td := llvm.NewTargetData("") // TODO(xsw): target config td := llvm.NewTargetData("") // TODO(xsw): target config
return &aProgram{ctx: ctx, target: target, td: td} return &aProgram{ctx: ctx, target: target, td: td}
} }
@@ -130,7 +131,8 @@ func NewProgram(target *Target) Program {
// NewPackage creates a new package. // NewPackage creates a new package.
func (p Program) NewPackage(name, pkgPath string) Package { func (p Program) NewPackage(name, pkgPath string) Package {
mod := p.ctx.NewModule(pkgPath) mod := p.ctx.NewModule(pkgPath)
mod.Finalize() // TODO(xsw): Finalize may cause panic, so comment it.
// mod.Finalize()
fns := make(map[string]Function) fns := make(map[string]Function)
gbls := make(map[string]Global) gbls := make(map[string]Global)
return &aPackage{mod, fns, gbls, p} return &aPackage{mod, fns, gbls, p}