From edaba44c87f6fffbac1594cffa9b748be3dcc6d8 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 17 Jun 2024 23:51:40 +0800 Subject: [PATCH] c/pthread/sync.Mutex; sync.Mutex/Once; typepatch.IsPatched --- c/pthread/sync/sync.go | 43 +++++ cl/compile.go | 301 +------------------------------- cl/import.go | 3 +- cl/instr.go | 333 ++++++++++++++++++++++++++++++++++++ internal/lib/sync/sync.go | 55 +++--- internal/typepatch/patch.go | 20 ++- 6 files changed, 432 insertions(+), 323 deletions(-) create mode 100644 cl/instr.go diff --git a/c/pthread/sync/sync.go b/c/pthread/sync/sync.go index 9fd3dd03..a3445a04 100644 --- a/c/pthread/sync/sync.go +++ b/c/pthread/sync/sync.go @@ -42,3 +42,46 @@ var OnceInit Once func (o *Once) Do(f func()) c.Int { return 0 } // ----------------------------------------------------------------------------- + +type MutexType c.Int + +const ( + MutexNormal MutexType = C.PTHREAD_MUTEX_NORMAL + MutexErrorCheck MutexType = C.PTHREAD_MUTEX_ERRORCHECK + MutexRecursive MutexType = C.PTHREAD_MUTEX_RECURSIVE + MutexDefault MutexType = C.PTHREAD_MUTEX_DEFAULT +) + +// MutexAttr is a mutex attribute object. +type MutexAttr C.pthread_mutexattr_t + +// llgo:link (*MutexAttr).Init C.pthread_mutexattr_init +func (a *MutexAttr) Init(attr *MutexAttr) c.Int { return 0 } + +// llgo:link (*MutexAttr).Destroy C.pthread_mutexattr_destroy +func (a *MutexAttr) Destroy() {} + +// llgo:link (*MutexAttr).SetType C.pthread_mutexattr_settype +func (a *MutexAttr) SetType(typ MutexType) c.Int { return 0 } + +// ----------------------------------------------------------------------------- + +// Mutex is a mutual exclusion lock. +type Mutex C.pthread_mutex_t + +// llgo:link (*Mutex).Init C.pthread_mutex_init +func (m *Mutex) Init(attr *MutexAttr) c.Int { return 0 } + +// llgo:link (*Mutex).Destroy C.pthread_mutex_destroy +func (m *Mutex) Destroy() {} + +// llgo:link (*Mutex).Lock C.pthread_mutex_lock +func (m *Mutex) Lock() {} + +// llgo:link (*Mutex).TryLock C.pthread_mutex_trylock +func (m *Mutex) TryLock() c.Int { return 0 } + +// llgo:link (*Mutex).Unlock C.pthread_mutex_unlock +func (m *Mutex) Unlock() {} + +// ----------------------------------------------------------------------------- diff --git a/cl/compile.go b/cl/compile.go index a6c38703..bc06d390 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -28,8 +28,9 @@ import ( "github.com/goplus/llgo/cl/blocks" "github.com/goplus/llgo/internal/typepatch" - llssa "github.com/goplus/llgo/ssa" "golang.org/x/tools/go/ssa" + + llssa "github.com/goplus/llgo/ssa" ) // ----------------------------------------------------------------------------- @@ -56,42 +57,6 @@ func SetDebug(dbgFlags dbgFlags) { // ----------------------------------------------------------------------------- -const ( - fnNormal = iota - fnHasVArg - fnIgnore -) - -func (p *context) funcKind(vfn ssa.Value) int { - if fn, ok := vfn.(*ssa.Function); ok { - params := fn.Signature.Params() - n := params.Len() - if n == 0 { - if fn.Signature.Recv() == nil { - if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) { - return fnIgnore - } - } - } else { - last := params.At(n - 1) - if last.Name() == llssa.NameValist { - return fnHasVArg - } - } - } - return fnNormal -} - -func (p *context) pkgNoInit(pkg *types.Package) bool { - p.ensureLoaded(pkg) - if i, ok := p.loaded[pkg]; ok { - return i.kind >= PkgNoInit - } - return false -} - -// ----------------------------------------------------------------------------- - type instrOrValue interface { ssa.Instruction ssa.Value @@ -287,69 +252,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun return fn, nil, goFunc } -var llgoInstrs = map[string]int{ - "cstr": llgoCstr, - "advance": llgoAdvance, - "index": llgoIndex, - "alloca": llgoAlloca, - "allocaCStr": llgoAllocaCStr, - "stringData": llgoStringData, - "pyList": llgoPyList, - "sigjmpbuf": llgoSigjmpbuf, - "sigsetjmp": llgoSigsetjmp, - "siglongjmp": llgoSiglongjmp, - "deferData": llgoDeferData, - "unreachable": llgoUnreachable, - - "atomicLoad": llgoAtomicLoad, - "atomicStore": llgoAtomicStore, - "atomicCmpXchg": llgoAtomicCmpXchg, - - "atomicXchg": int(llgoAtomicXchg), - "atomicAdd": int(llgoAtomicAdd), - "atomicSub": int(llgoAtomicSub), - "atomicAnd": int(llgoAtomicAnd), - "atomicNand": int(llgoAtomicNand), - "atomicOr": int(llgoAtomicOr), - "atomicXor": int(llgoAtomicXor), - "atomicMax": int(llgoAtomicMax), - "atomicMin": int(llgoAtomicMin), - "atomicUMax": int(llgoAtomicUMax), - "atomicUMin": int(llgoAtomicUMin), -} - -// funcOf returns a function by name and set ftype = goFunc, cFunc, etc. -// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc. -func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) { - pkgTypes, name, ftype := p.funcName(fn, false) - switch ftype { - case pyFunc: - if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule { - pkg := p.pkg - fnName := pysymPrefix + mod + "." + name - if pyFn = pkg.PyObjOf(fnName); pyFn == nil { - pyFn = pkg.PyNewFunc(fnName, fn.Signature, true) - } - return - } - ftype = ignoredFunc - case llgoInstr: - if ftype = llgoInstrs[name]; ftype == 0 { - panic("unknown llgo instruction: " + name) - } - default: - pkg := p.pkg - if aFn = pkg.FuncOf(name); aFn == nil { - if len(fn.FreeVars) > 0 { - return nil, nil, ignoredFunc - } - sig := fn.Signature - aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false) - } - } - return -} - func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doMainInit, doModInit bool) llssa.BasicBlock { var last int var pyModInit bool @@ -467,117 +369,6 @@ func isAllocVargs(ctx *context, v *ssa.Alloc) bool { return false } -// func cstr(string) *int8 -func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 1 { - if c, ok := args[0].(*ssa.Const); ok { - if v := c.Value; v.Kind() == constant.String { - sv := constant.StringVal(v) - return b.CStr(sv) - } - } - } - panic("cstr(): invalid arguments") -} - -// func index(arr *T, idx int) T -func (p *context) index(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - return b.Load(p.advance(b, args)) -} - -// func advance(ptr *T, offset int) *T -func (p *context) advance(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 2 { - ptr := p.compileValue(b, args[0]) - offset := p.compileValue(b, args[1]) - return b.Advance(ptr, offset) - } - panic("advance(p ptr, offset int): invalid arguments") -} - -// func alloca(size uintptr) unsafe.Pointer -func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 1 { - n := p.compileValue(b, args[0]) - return b.Alloca(n) - } - panic("alloca(size uintptr): invalid arguments") -} - -// func allocaCStr(s string) *int8 -func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 1 { - s := p.compileValue(b, args[0]) - return b.AllocaCStr(s) - } - panic("allocaCStr(s string): invalid arguments") -} - -// func stringData(s string) *int8 -func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 1 { - s := p.compileValue(b, args[0]) - return b.StringData(s) - } - panic("stringData(s string): invalid arguments") -} - -func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 2 { - jb := p.compileValue(b, args[0]) - savemask := p.compileValue(b, args[1]) - return b.Sigsetjmp(jb, savemask) - } - panic("sigsetjmp(jb c.SigjmpBuf, savemask c.Int): invalid arguments") -} - -func (p *context) siglongjmp(b llssa.Builder, args []ssa.Value) { - if len(args) == 2 { - jb := p.compileValue(b, args[0]) - retval := p.compileValue(b, args[1]) - b.Siglongjmp(jb, retval) - return - } - panic("siglongjmp(jb c.SigjmpBuf, retval c.Int): invalid arguments") -} - -func (p *context) atomic(b llssa.Builder, op llssa.AtomicOp, args []ssa.Value) (ret llssa.Expr) { - if len(args) == 2 { - addr := p.compileValue(b, args[0]) - val := p.compileValue(b, args[1]) - return b.Atomic(op, addr, val) - } - panic("atomicOp(addr *T, val T) T: invalid arguments") -} - -func (p *context) atomicLoad(b llssa.Builder, args []ssa.Value) llssa.Expr { - if len(args) == 1 { - addr := p.compileValue(b, args[0]) - return b.Load(addr).SetOrdering(llssa.OrderingSeqConsistent) - } - panic("atomicLoad(addr *T) T: invalid arguments") -} - -func (p *context) atomicStore(b llssa.Builder, args []ssa.Value) { - if len(args) == 2 { - addr := p.compileValue(b, args[0]) - val := p.compileValue(b, args[1]) - b.Store(addr, val).SetOrdering(llssa.OrderingSeqConsistent) - return - } - panic("atomicStore(addr *T, val T) T: invalid arguments") -} - -func (p *context) atomicCmpXchg(b llssa.Builder, args []ssa.Value) llssa.Expr { - if len(args) == 3 { - addr := p.compileValue(b, args[0]) - old := p.compileValue(b, args[1]) - new := p.compileValue(b, args[2]) - return b.AtomicCmpXchg(addr, old, new) - } - panic("atomicCmpXchg(addr *T, old, new T) T: invalid arguments") -} - func isPhi(i ssa.Instruction) bool { _, ok := i.(*ssa.Phi) return ok @@ -629,94 +420,6 @@ func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) { return } -func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) { - cv := call.Value - if mthd := call.Method; mthd != nil { - o := p.compileValue(b, cv) - fn := b.Imethod(o, mthd) - args := p.compileValues(b, call.Args, fnNormal) - ret = b.Do(act, fn, args...) - return - } - kind := p.funcKind(cv) - if kind == fnIgnore { - return - } - args := call.Args - if debugGoSSA { - log.Println(">>> Do", act, cv, args) - } - switch cv := cv.(type) { - case *ssa.Builtin: - fn := cv.Name() - if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr - arg := args[0] - ret = p.compileValue(b, arg) - } else { - args := p.compileValues(b, args, kind) - ret = b.Do(act, llssa.Builtin(fn), args...) - } - case *ssa.Function: - aFn, pyFn, ftype := p.compileFunction(cv) - // TODO(xsw): check ca != llssa.Call - switch ftype { - case cFunc: - p.inCFunc = true - args := p.compileValues(b, args, kind) - p.inCFunc = false - ret = b.Do(act, aFn.Expr, args...) - case goFunc: - args := p.compileValues(b, args, kind) - ret = b.Do(act, aFn.Expr, args...) - case pyFunc: - args := p.compileValues(b, args, kind) - ret = b.Do(act, pyFn.Expr, args...) - case llgoPyList: - args := p.compileValues(b, args, fnHasVArg) - ret = b.PyList(args...) - case llgoCstr: - ret = cstr(b, args) - case llgoAdvance: - ret = p.advance(b, args) - case llgoIndex: - ret = p.index(b, args) - case llgoAlloca: - ret = p.alloca(b, args) - case llgoAllocaCStr: - ret = p.allocaCStr(b, args) - case llgoStringData: - ret = p.stringData(b, args) - case llgoAtomicLoad: - ret = p.atomicLoad(b, args) - case llgoAtomicStore: - p.atomicStore(b, args) - case llgoAtomicCmpXchg: - ret = p.atomicCmpXchg(b, args) - case llgoSigsetjmp: - ret = p.sigsetjmp(b, args) - case llgoSiglongjmp: - p.siglongjmp(b, args) - case llgoSigjmpbuf: // func sigjmpbuf() - ret = b.AllocaSigjmpBuf() - case llgoDeferData: // func deferData() *Defer - ret = b.DeferData() - case llgoUnreachable: // func unreachable() - b.Unreachable() - default: - if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast { - ret = p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args) - } else { - log.Panicln("unknown ftype:", ftype) - } - } - default: - fn := p.compileValue(b, cv) - args := p.compileValues(b, args, kind) - ret = b.Do(act, fn, args...) - } - return -} - func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) { if asValue { if v, ok := p.bvals[iv]; ok { diff --git a/cl/import.go b/cl/import.go index fc1bc46d..d1f337cb 100644 --- a/cl/import.go +++ b/cl/import.go @@ -26,8 +26,9 @@ import ( "os" "strings" - llssa "github.com/goplus/llgo/ssa" "golang.org/x/tools/go/ssa" + + llssa "github.com/goplus/llgo/ssa" ) // ----------------------------------------------------------------------------- diff --git a/cl/instr.go b/cl/instr.go new file mode 100644 index 00000000..9edc144e --- /dev/null +++ b/cl/instr.go @@ -0,0 +1,333 @@ +/* + * 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 cl + +import ( + "go/constant" + "go/types" + "log" + + "golang.org/x/tools/go/ssa" + + llssa "github.com/goplus/llgo/ssa" +) + +// ----------------------------------------------------------------------------- + +// func cstr(string) *int8 +func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 1 { + if c, ok := args[0].(*ssa.Const); ok { + if v := c.Value; v.Kind() == constant.String { + sv := constant.StringVal(v) + return b.CStr(sv) + } + } + } + panic("cstr(): invalid arguments") +} + +// func index(arr *T, idx int) T +func (p *context) index(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + return b.Load(p.advance(b, args)) +} + +// func advance(ptr *T, offset int) *T +func (p *context) advance(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 2 { + ptr := p.compileValue(b, args[0]) + offset := p.compileValue(b, args[1]) + return b.Advance(ptr, offset) + } + panic("advance(p ptr, offset int): invalid arguments") +} + +// func alloca(size uintptr) unsafe.Pointer +func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 1 { + n := p.compileValue(b, args[0]) + return b.Alloca(n) + } + panic("alloca(size uintptr): invalid arguments") +} + +// func allocaCStr(s string) *int8 +func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 1 { + s := p.compileValue(b, args[0]) + return b.AllocaCStr(s) + } + panic("allocaCStr(s string): invalid arguments") +} + +// func stringData(s string) *int8 +func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 1 { + s := p.compileValue(b, args[0]) + return b.StringData(s) + } + panic("stringData(s string): invalid arguments") +} + +func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 2 { + jb := p.compileValue(b, args[0]) + savemask := p.compileValue(b, args[1]) + return b.Sigsetjmp(jb, savemask) + } + panic("sigsetjmp(jb c.SigjmpBuf, savemask c.Int): invalid arguments") +} + +func (p *context) siglongjmp(b llssa.Builder, args []ssa.Value) { + if len(args) == 2 { + jb := p.compileValue(b, args[0]) + retval := p.compileValue(b, args[1]) + b.Siglongjmp(jb, retval) + return + } + panic("siglongjmp(jb c.SigjmpBuf, retval c.Int): invalid arguments") +} + +func (p *context) atomic(b llssa.Builder, op llssa.AtomicOp, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 2 { + addr := p.compileValue(b, args[0]) + val := p.compileValue(b, args[1]) + return b.Atomic(op, addr, val) + } + panic("atomicOp(addr *T, val T) T: invalid arguments") +} + +func (p *context) atomicLoad(b llssa.Builder, args []ssa.Value) llssa.Expr { + if len(args) == 1 { + addr := p.compileValue(b, args[0]) + return b.Load(addr).SetOrdering(llssa.OrderingSeqConsistent) + } + panic("atomicLoad(addr *T) T: invalid arguments") +} + +func (p *context) atomicStore(b llssa.Builder, args []ssa.Value) { + if len(args) == 2 { + addr := p.compileValue(b, args[0]) + val := p.compileValue(b, args[1]) + b.Store(addr, val).SetOrdering(llssa.OrderingSeqConsistent) + return + } + panic("atomicStore(addr *T, val T) T: invalid arguments") +} + +func (p *context) atomicCmpXchg(b llssa.Builder, args []ssa.Value) llssa.Expr { + if len(args) == 3 { + addr := p.compileValue(b, args[0]) + old := p.compileValue(b, args[1]) + new := p.compileValue(b, args[2]) + return b.AtomicCmpXchg(addr, old, new) + } + panic("atomicCmpXchg(addr *T, old, new T) T: invalid arguments") +} + +// ----------------------------------------------------------------------------- + +var llgoInstrs = map[string]int{ + "cstr": llgoCstr, + "advance": llgoAdvance, + "index": llgoIndex, + "alloca": llgoAlloca, + "allocaCStr": llgoAllocaCStr, + "stringData": llgoStringData, + "pyList": llgoPyList, + "sigjmpbuf": llgoSigjmpbuf, + "sigsetjmp": llgoSigsetjmp, + "siglongjmp": llgoSiglongjmp, + "deferData": llgoDeferData, + "unreachable": llgoUnreachable, + + "atomicLoad": llgoAtomicLoad, + "atomicStore": llgoAtomicStore, + "atomicCmpXchg": llgoAtomicCmpXchg, + + "atomicXchg": int(llgoAtomicXchg), + "atomicAdd": int(llgoAtomicAdd), + "atomicSub": int(llgoAtomicSub), + "atomicAnd": int(llgoAtomicAnd), + "atomicNand": int(llgoAtomicNand), + "atomicOr": int(llgoAtomicOr), + "atomicXor": int(llgoAtomicXor), + "atomicMax": int(llgoAtomicMax), + "atomicMin": int(llgoAtomicMin), + "atomicUMax": int(llgoAtomicUMax), + "atomicUMin": int(llgoAtomicUMin), +} + +// funcOf returns a function by name and set ftype = goFunc, cFunc, etc. +// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc. +func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) { + pkgTypes, name, ftype := p.funcName(fn, false) + switch ftype { + case pyFunc: + if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule { + pkg := p.pkg + fnName := pysymPrefix + mod + "." + name + if pyFn = pkg.PyObjOf(fnName); pyFn == nil { + pyFn = pkg.PyNewFunc(fnName, fn.Signature, true) + } + return + } + ftype = ignoredFunc + case llgoInstr: + if ftype = llgoInstrs[name]; ftype == 0 { + panic("unknown llgo instruction: " + name) + } + default: + pkg := p.pkg + if aFn = pkg.FuncOf(name); aFn == nil { + if len(fn.FreeVars) > 0 { + return nil, nil, ignoredFunc + } + sig := fn.Signature + aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false) + } + } + return +} + +// ----------------------------------------------------------------------------- + +const ( + fnNormal = iota + fnHasVArg + fnIgnore +) + +func (p *context) funcKind(vfn ssa.Value) int { + if fn, ok := vfn.(*ssa.Function); ok { + params := fn.Signature.Params() + n := params.Len() + if n == 0 { + if fn.Signature.Recv() == nil { + if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) { + return fnIgnore + } + } + } else { + last := params.At(n - 1) + if last.Name() == llssa.NameValist { + return fnHasVArg + } + } + } + return fnNormal +} + +func (p *context) pkgNoInit(pkg *types.Package) bool { + p.ensureLoaded(pkg) + if i, ok := p.loaded[pkg]; ok { + return i.kind >= PkgNoInit + } + return false +} + +// ----------------------------------------------------------------------------- + +func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) { + cv := call.Value + if mthd := call.Method; mthd != nil { + o := p.compileValue(b, cv) + fn := b.Imethod(o, mthd) + args := p.compileValues(b, call.Args, fnNormal) + ret = b.Do(act, fn, args...) + return + } + kind := p.funcKind(cv) + if kind == fnIgnore { + return + } + args := call.Args + if debugGoSSA { + log.Println(">>> Do", act, cv, args) + } + switch cv := cv.(type) { + case *ssa.Builtin: + fn := cv.Name() + if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr + arg := args[0] + ret = p.compileValue(b, arg) + } else { + args := p.compileValues(b, args, kind) + ret = b.Do(act, llssa.Builtin(fn), args...) + } + case *ssa.Function: + aFn, pyFn, ftype := p.compileFunction(cv) + // TODO(xsw): check ca != llssa.Call + switch ftype { + case cFunc: + p.inCFunc = true + args := p.compileValues(b, args, kind) + p.inCFunc = false + ret = b.Do(act, aFn.Expr, args...) + case goFunc: + args := p.compileValues(b, args, kind) + ret = b.Do(act, aFn.Expr, args...) + case pyFunc: + args := p.compileValues(b, args, kind) + ret = b.Do(act, pyFn.Expr, args...) + case llgoPyList: + args := p.compileValues(b, args, fnHasVArg) + ret = b.PyList(args...) + case llgoCstr: + ret = cstr(b, args) + case llgoAdvance: + ret = p.advance(b, args) + case llgoIndex: + ret = p.index(b, args) + case llgoAlloca: + ret = p.alloca(b, args) + case llgoAllocaCStr: + ret = p.allocaCStr(b, args) + case llgoStringData: + ret = p.stringData(b, args) + case llgoAtomicLoad: + ret = p.atomicLoad(b, args) + case llgoAtomicStore: + p.atomicStore(b, args) + case llgoAtomicCmpXchg: + ret = p.atomicCmpXchg(b, args) + case llgoSigsetjmp: + ret = p.sigsetjmp(b, args) + case llgoSiglongjmp: + p.siglongjmp(b, args) + case llgoSigjmpbuf: // func sigjmpbuf() + ret = b.AllocaSigjmpBuf() + case llgoDeferData: // func deferData() *Defer + ret = b.DeferData() + case llgoUnreachable: // func unreachable() + b.Unreachable() + default: + if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast { + ret = p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args) + } else { + log.Panicln("unknown ftype:", ftype) + } + } + default: + fn := p.compileValue(b, cv) + args := p.compileValues(b, args, kind) + ret = b.Do(act, fn, args...) + } + return +} + +// ----------------------------------------------------------------------------- diff --git a/internal/lib/sync/sync.go b/internal/lib/sync/sync.go index 35ad736b..0d229513 100644 --- a/internal/lib/sync/sync.go +++ b/internal/lib/sync/sync.go @@ -21,7 +21,6 @@ import ( "unsafe" "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/pthread" "github.com/goplus/llgo/c/pthread/sync" ) @@ -31,29 +30,43 @@ const ( // ----------------------------------------------------------------------------- -var onceParam pthread.Key +type Mutex sync.Mutex -func init() { - onceParam.Create(nil) -} - -type Once sync.Once - -func (o *Once) Do(f func()) { - ptr := c.Malloc(unsafe.Sizeof(f)) - *(*func())(ptr) = f - onceParam.Set(ptr) - if *(*c.Long)(unsafe.Pointer(o)) == 0 { // try init - *(*sync.Once)(o) = sync.OnceInit +func (m *Mutex) Lock() { + if *(*c.Long)(unsafe.Pointer(m)) == 0 { + (*sync.Mutex)(m).Init(nil) } - onceDo(o, func() { - ptr := onceParam.Get() - (*(*func())(ptr))() - c.Free(ptr) - }) + (*sync.Mutex)(m).Lock() } -//go:linkname onceDo C.pthread_once -func onceDo(o *Once, f func()) c.Int +func (m *Mutex) TryLock() bool { + if *(*c.Long)(unsafe.Pointer(m)) == 0 { + (*sync.Mutex)(m).Init(nil) + } + return (*sync.Mutex)(m).TryLock() == 0 +} + +func (m *Mutex) Unlock() { + (*sync.Mutex)(m).Unlock() +} + +// ----------------------------------------------------------------------------- + +type Once struct { + m Mutex + done bool +} + +func (o *Once) Do(f func()) { + println("Once.Do start", o.done) + if !o.done { + o.m.Lock() + defer o.m.Unlock() + if !o.done { + o.done = true + f() + } + } +} // ----------------------------------------------------------------------------- diff --git a/internal/typepatch/patch.go b/internal/typepatch/patch.go index 4555779b..df0f0e21 100644 --- a/internal/typepatch/patch.go +++ b/internal/typepatch/patch.go @@ -55,14 +55,29 @@ type iface struct { data unsafe.Pointer } +const ( + tagPatched = 0x17 +) + +func IsPatched(pkg *types.Package) bool { + p := (*typesPackage)(unsafe.Pointer(pkg)) + return *(*uint8)(unsafe.Pointer(&p.complete)) == tagPatched +} + +func setPatched(pkg *types.Package) { + p := (*typesPackage)(unsafe.Pointer(pkg)) + *(*uint8)(unsafe.Pointer(&p.complete)) = tagPatched +} + func setScope(pkg *types.Package, scope *types.Scope) { p := (*typesPackage)(unsafe.Pointer(pkg)) p.scope = scope } -func setPkg(o types.Object, pkg *types.Package) { +func setPkgAndParent(o types.Object, pkg *types.Package, parent *types.Scope) { data := (*iface)(unsafe.Pointer(&o)).data (*object)(data).pkg = pkg + (*object)(data).parent = parent } func getElems(scope *types.Scope) map[string]types.Object { @@ -87,10 +102,11 @@ func Pkg(pkg, alt *types.Package) *types.Package { altScope := alt.Scope() for name, o := range getElems(altScope) { - setPkg(o, pkg) + setPkgAndParent(o, &ret, &scope) elems[name] = o } setElems(&scope, elems) setScope(&ret, &scope) + setPatched(pkg) return &ret }