diff --git a/cl/_testlibgo/_errors/in.go b/cl/_testlibgo/_errors/in.go new file mode 100644 index 00000000..e833b256 --- /dev/null +++ b/cl/_testlibgo/_errors/in.go @@ -0,0 +1,8 @@ +package main + +import "errors" + +func main() { + err := errors.New("error") + panic(err) +} diff --git a/cl/compile.go b/cl/compile.go index 3136a2a5..4b72f945 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -100,12 +100,23 @@ type context struct { inits []func() phis []func() + state pkgState inCFunc bool skipall bool } +type pkgState byte + +const ( + pkgNormal pkgState = iota + pkgHasPatch + pkgInPatch + + pkgFNoOldInit = 0x80 // flag if no initFnNameOld +) + func (p *context) inMain(instr ssa.Instruction) bool { - return instr.Parent().Name() == "main" + return p.fn.Name() == "main" } func (p *context) compileType(pkg llssa.Package, t *ssa.Type) { @@ -184,6 +195,8 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun return fn, nil, goFunc } + var isInit bool + var state = p.state var sig = f.Signature var hasCtx = len(f.FreeVars) > 0 if hasCtx { @@ -196,6 +209,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun if debugInstr { log.Println("==> NewFunc", name, "type:", sig.Recv(), sig, "ftype:", ftype) } + isInit = (f.Name() == "init" && sig.Recv() == nil) } if fn == nil { if name == "main" { @@ -205,14 +219,20 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun ret := types.NewParam(token.NoPos, pkgTypes, "", p.prog.CInt().RawType()) results := types.NewTuple(ret) sig = types.NewSignatureType(nil, nil, nil, params, results, false) + } else if isInit && state == pkgHasPatch { + name = initFnNameOfHasPatch(name) } fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx) } if nblk := len(f.Blocks); nblk > 0 { - fn.MakeBlocks(nblk) // to set fn.HasBody() = true + fn.MakeBlocks(nblk) // to set fn.HasBody() = true + if f.Recover != nil { // set recover block + fn.SetRecover(fn.Block(f.Recover.Index)) + } p.inits = append(p.inits, func() { p.fn = fn + p.state = state // restore pkgState when compiling funcBody defer func() { p.fn = nil }() @@ -234,7 +254,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun for { block := f.Blocks[i] doMainInit := (i == 0 && name == "main") - doModInit := (i == 1 && f.Name() == "init" && sig.Recv() == nil) + doModInit := (i == 1 && isInit) p.compileBlock(b, block, off[i], doMainInit, doModInit) if i = p.blkInfos[i].Next; i < 0 { break @@ -257,8 +277,9 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do var pyModInit bool var prog = p.prog var pkg = p.pkg + var fn = p.fn var instrs = block.Instrs[n:] - var ret = p.fn.Block(block.Index) + var ret = fn.Block(block.Index) b.SetBlock(ret) if doModInit { if pyModInit = p.pyMod != ""; pyModInit { @@ -271,7 +292,6 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do }) } } else if doMainInit { - fn := p.fn argc := pkg.NewVar("__llgo_argc", types.NewPointer(types.Typ[types.Int32]), llssa.InC) argv := pkg.NewVar("__llgo_argv", types.NewPointer(argvTy), llssa.InC) argc.InitNil() @@ -281,7 +301,12 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do callRuntimeInit(b, pkg) b.Call(pkg.FuncOf("main.init").Expr) } - for _, instr := range instrs { + for i, instr := range instrs { + if i == 1 && doModInit && p.state == pkgInPatch { + initFnNameOld := initFnNameOfHasPatch(p.fn.Name()) + fnOld := pkg.NewFunc(initFnNameOld, llssa.NoArgsNoRet, llssa.InC) + b.Call(fnOld.Expr) + } p.compileInstr(b, instr) } if pyModInit { @@ -292,7 +317,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do modPtr := pkg.PyNewModVar(modName, true).Expr mod := b.Load(modPtr) cond := b.BinOp(token.NEQ, mod, prog.Nil(mod.Type)) - newBlk := p.fn.MakeBlock() + newBlk := fn.MakeBlock() b.If(cond, jumpTo, newBlk) b.SetBlockEx(newBlk, llssa.AtEnd, false) b.Store(modPtr, b.PyImportMod(modPath)) @@ -377,9 +402,6 @@ func isPhi(i ssa.Instruction) bool { func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int { fn := p.fn ret := fn.Block(block.Index) - if block.Comment == "recover" { // set recover block - fn.SetRecover(ret) - } b.SetBlockEx(ret, llssa.AtEnd, false) if ninstr := len(block.Instrs); ninstr > 0 { if isPhi(block.Instrs[0]) { @@ -752,7 +774,12 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [ if hasPatch { skips := ctx.skips ctx.skips = nil + ctx.state = pkgInPatch + if _, ok := skips["init"]; ok || ctx.skipall { + ctx.state |= pkgFNoOldInit + } processPkg(ctx, ret, alt) + ctx.state = pkgHasPatch ctx.skips = skips } if !ctx.skipall { @@ -768,6 +795,10 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [ return } +func initFnNameOfHasPatch(name string) string { + return name + "$hasPatch" +} + func processPkg(ctx *context, ret llssa.Package, pkg *ssa.Package) { type namedMember struct { name string diff --git a/cl/import.go b/cl/import.go index cf71b379..63d80bb4 100644 --- a/cl/import.go +++ b/cl/import.go @@ -507,8 +507,7 @@ func ignoreName(name string) bool { strings.HasPrefix(name, "arena.") || strings.HasPrefix(name, "maps.") || strings.HasPrefix(name, "time.") || strings.HasPrefix(name, "syscall.") || strings.HasPrefix(name, "os.") || strings.HasPrefix(name, "plugin.") || - strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "errors.") || - strings.HasPrefix(name, "runtime/") + strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "runtime/") } // ----------------------------------------------------------------------------- diff --git a/internal/build/build.go b/internal/build/build.go index b25ef650..e3e1da8e 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -706,7 +706,7 @@ func decodeFile(outFile string, zipf *zip.File) (err error) { func canSkipToBuild(pkgPath string) bool { switch pkgPath { - case "unsafe", "errors": // TODO(xsw): remove it + case "unsafe": return true default: return strings.HasPrefix(pkgPath, "internal/") || @@ -717,6 +717,7 @@ func canSkipToBuild(pkgPath string) bool { type none struct{} var hasAltPkg = map[string]none{ + "errors": {}, "math": {}, "sync": {}, "sync/atomic": {}, diff --git a/internal/lib/errors/errors.go b/internal/lib/errors/errors.go new file mode 100644 index 00000000..465fac10 --- /dev/null +++ b/internal/lib/errors/errors.go @@ -0,0 +1,17 @@ +/* + * 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 errors diff --git a/ssa/decl.go b/ssa/decl.go index 9e4a6ca6..89128409 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -234,12 +234,10 @@ func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { return } -/* // Name returns the function's name. func (p Function) Name() string { return p.impl.Name() } -*/ // Params returns the function's ith parameter. func (p Function) Param(i int) Expr {