first version of 'spawn'
This commit is contained in:
parent
b961e47bfe
commit
8e08ff559f
9 changed files with 188 additions and 37 deletions
|
|
@ -559,7 +559,7 @@ type
|
||||||
mFloat, mFloat32, mFloat64, mFloat128,
|
mFloat, mFloat32, mFloat64, mFloat128,
|
||||||
mBool, mChar, mString, mCstring,
|
mBool, mChar, mString, mCstring,
|
||||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
||||||
mVoidType, mPNimrodNode, mShared, mGuarded,
|
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn,
|
||||||
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
||||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||||
mNaN, mInf, mNegInf,
|
mNaN, mInf, mNegInf,
|
||||||
|
|
|
||||||
|
|
@ -1632,6 +1632,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
||||||
of mSlurp..mQuoteAst:
|
of mSlurp..mQuoteAst:
|
||||||
localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
|
localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
|
||||||
|
of mSpawn:
|
||||||
|
let n = lowerings.wrapProcForSpawn(p.module.module, e.sons[1])
|
||||||
|
expr(p, n, d)
|
||||||
else: internalError(e.info, "genMagicExpr: " & $op)
|
else: internalError(e.info, "genMagicExpr: " & $op)
|
||||||
|
|
||||||
proc genConstExpr(p: BProc, n: PNode): PRope
|
proc genConstExpr(p: BProc, n: PNode): PRope
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import
|
||||||
options, intsets,
|
options, intsets,
|
||||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||||
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases
|
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings
|
||||||
|
|
||||||
when options.hasTinyCBackend:
|
when options.hasTinyCBackend:
|
||||||
import tccgen
|
import tccgen
|
||||||
|
|
|
||||||
|
|
@ -141,12 +141,6 @@ type
|
||||||
closureParam, state, resultSym: PSym # only if isIter
|
closureParam, state, resultSym: PSym # only if isIter
|
||||||
obj: PType # only if isIter
|
obj: PType # only if isIter
|
||||||
|
|
||||||
proc createObj(owner: PSym, info: TLineInfo): PType =
|
|
||||||
result = newType(tyObject, owner)
|
|
||||||
rawAddSon(result, nil)
|
|
||||||
incl result.flags, tfFinal
|
|
||||||
result.n = newNodeI(nkRecList, info)
|
|
||||||
|
|
||||||
proc getStateType(iter: PSym): PType =
|
proc getStateType(iter: PSym): PType =
|
||||||
var n = newNodeI(nkRange, iter.info)
|
var n = newNodeI(nkRange, iter.info)
|
||||||
addSon(n, newIntNode(nkIntLit, -1))
|
addSon(n, newIntNode(nkIntLit, -1))
|
||||||
|
|
@ -190,15 +184,6 @@ proc getEnvParam(routine: PSym): PSym =
|
||||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||||
result = hidden.sym
|
result = hidden.sym
|
||||||
|
|
||||||
proc addField(obj: PType; s: PSym) =
|
|
||||||
# because of 'gensym' support, we have to mangle the name with its ID.
|
|
||||||
# This is hacky but the clean solution is much more complex than it looks.
|
|
||||||
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
|
|
||||||
let t = skipIntLit(s.typ)
|
|
||||||
field.typ = t
|
|
||||||
field.position = sonsLen(obj.n)
|
|
||||||
addSon(obj.n, newSymNode(field))
|
|
||||||
|
|
||||||
proc initIterContext(c: POuterContext, iter: PSym) =
|
proc initIterContext(c: POuterContext, iter: PSym) =
|
||||||
c.fn = iter
|
c.fn = iter
|
||||||
c.capturedVars = initIntSet()
|
c.capturedVars = initIntSet()
|
||||||
|
|
@ -274,22 +259,6 @@ proc addDep(e, d: PEnv, owner: PSym): PSym =
|
||||||
addField(e.obj, result)
|
addField(e.obj, result)
|
||||||
e.deps.add((d, result))
|
e.deps.add((d, result))
|
||||||
|
|
||||||
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
|
|
||||||
# returns a[].b as a node
|
|
||||||
var deref = newNodeI(nkHiddenDeref, info)
|
|
||||||
deref.typ = a.typ.sons[0]
|
|
||||||
assert deref.typ.kind == tyObject
|
|
||||||
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
|
|
||||||
assert field != nil, b.name.s
|
|
||||||
addSon(deref, a)
|
|
||||||
result = newNodeI(nkDotExpr, info)
|
|
||||||
addSon(result, deref)
|
|
||||||
addSon(result, newSymNode(field))
|
|
||||||
result.typ = field.typ
|
|
||||||
|
|
||||||
proc indirectAccess(a, b: PSym, info: TLineInfo): PNode =
|
|
||||||
result = indirectAccess(newSymNode(a), b, info)
|
|
||||||
|
|
||||||
proc newCall(a, b: PSym): PNode =
|
proc newCall(a, b: PSym): PNode =
|
||||||
result = newNodeI(nkCall, a.info)
|
result = newNodeI(nkCall, a.info)
|
||||||
result.add newSymNode(a)
|
result.add newSymNode(a)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
const
|
const
|
||||||
genPrefix* = ":tmp" # prefix for generated names
|
genPrefix* = ":tmp" # prefix for generated names
|
||||||
|
|
||||||
import ast, types, idents, magicsys
|
import ast, astalgo, types, idents, magicsys, msgs
|
||||||
|
|
||||||
proc newTupleAccess*(tup: PNode, i: int): PNode =
|
proc newTupleAccess*(tup: PNode, i: int): PNode =
|
||||||
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
|
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
|
||||||
|
|
@ -34,6 +34,11 @@ proc newAsgnStmt(le, ri: PNode): PNode =
|
||||||
result.sons[0] = le
|
result.sons[0] = le
|
||||||
result.sons[1] = ri
|
result.sons[1] = ri
|
||||||
|
|
||||||
|
proc newFastAsgnStmt(le, ri: PNode): PNode =
|
||||||
|
result = newNodeI(nkFastAsgn, le.info, 2)
|
||||||
|
result.sons[0] = le
|
||||||
|
result.sons[1] = ri
|
||||||
|
|
||||||
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
||||||
assert n.kind == nkVarTuple
|
assert n.kind == nkVarTuple
|
||||||
let value = n.lastSon
|
let value = n.lastSon
|
||||||
|
|
@ -50,3 +55,170 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
||||||
result.add newAsgnStmt(newSymNode(temp), value)
|
result.add newAsgnStmt(newSymNode(temp), value)
|
||||||
for i in 0 .. n.len-3:
|
for i in 0 .. n.len-3:
|
||||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
||||||
|
|
||||||
|
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||||
|
result = newType(tyObject, owner)
|
||||||
|
rawAddSon(result, nil)
|
||||||
|
incl result.flags, tfFinal
|
||||||
|
result.n = newNodeI(nkRecList, info)
|
||||||
|
|
||||||
|
proc addField*(obj: PType; s: PSym) =
|
||||||
|
# because of 'gensym' support, we have to mangle the name with its ID.
|
||||||
|
# This is hacky but the clean solution is much more complex than it looks.
|
||||||
|
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
|
||||||
|
let t = skipIntLit(s.typ)
|
||||||
|
field.typ = t
|
||||||
|
field.position = sonsLen(obj.n)
|
||||||
|
addSon(obj.n, newSymNode(field))
|
||||||
|
|
||||||
|
proc newDotExpr(obj, b: PSym): PNode =
|
||||||
|
result = newNodeI(nkDotExpr, obj.info)
|
||||||
|
let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
|
||||||
|
assert field != nil, b.name.s
|
||||||
|
addSon(result, newSymNode(obj))
|
||||||
|
addSon(result, newSymNode(field))
|
||||||
|
result.typ = field.typ
|
||||||
|
|
||||||
|
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||||
|
# returns a[].b as a node
|
||||||
|
var deref = newNodeI(nkHiddenDeref, info)
|
||||||
|
deref.typ = a.typ.sons[0]
|
||||||
|
assert deref.typ.kind == tyObject
|
||||||
|
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
|
||||||
|
assert field != nil, b.name.s
|
||||||
|
addSon(deref, a)
|
||||||
|
result = newNodeI(nkDotExpr, info)
|
||||||
|
addSon(result, deref)
|
||||||
|
addSon(result, newSymNode(field))
|
||||||
|
result.typ = field.typ
|
||||||
|
|
||||||
|
proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
|
||||||
|
result = indirectAccess(newSymNode(a), b, info)
|
||||||
|
|
||||||
|
proc genAddrOf*(n: PNode): PNode =
|
||||||
|
result = newNodeI(nkAddr, n.info, 1)
|
||||||
|
result.sons[0] = n
|
||||||
|
result.typ = newType(tyPtr, n.typ.owner)
|
||||||
|
result.typ.rawAddSon(n.typ)
|
||||||
|
|
||||||
|
proc callCodegenProc*(name: string, arg1: PNode;
|
||||||
|
arg2, arg3: PNode = nil): PNode =
|
||||||
|
result = newNodeI(nkCall, arg1.info)
|
||||||
|
let sym = magicsys.getCompilerProc(name)
|
||||||
|
if sym == nil:
|
||||||
|
localError(arg1.info, errSystemNeeds, name)
|
||||||
|
else:
|
||||||
|
result.add newSymNode(sym)
|
||||||
|
result.add arg1
|
||||||
|
if arg2 != nil: result.add arg2
|
||||||
|
if arg3 != nil: result.add arg3
|
||||||
|
|
||||||
|
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
|
varSection, call: PNode): PSym =
|
||||||
|
var body = newNodeI(nkStmtList, f.info)
|
||||||
|
body.add varSection
|
||||||
|
body.add callCodeGenProc("nimArgsPassingDone", newSymNode(threadParam))
|
||||||
|
body.add call
|
||||||
|
|
||||||
|
var params = newNodeI(nkFormalParams, f.info)
|
||||||
|
params.add emptyNode
|
||||||
|
params.add threadParam.newSymNode
|
||||||
|
params.add argsParam.newSymNode
|
||||||
|
|
||||||
|
var t = newType(tyProc, threadParam.owner)
|
||||||
|
t.rawAddSon nil
|
||||||
|
t.rawAddSon threadParam.typ
|
||||||
|
t.rawAddSon argsParam.typ
|
||||||
|
t.n = newNodeI(nkFormalParams, f.info)
|
||||||
|
t.n.add newNodeI(nkEffectList, f.info)
|
||||||
|
t.n.add threadParam.newSymNode
|
||||||
|
t.n.add argsParam.newSymNode
|
||||||
|
|
||||||
|
let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
|
||||||
|
result = newSym(skProc, getIdent(name), argsParam.owner, f.info)
|
||||||
|
result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
|
||||||
|
result.typ = t
|
||||||
|
|
||||||
|
proc createCastExpr(argsParam: PSym; objType: PType): PNode =
|
||||||
|
result = newNodeI(nkCast, argsParam.info)
|
||||||
|
result.add emptyNode
|
||||||
|
result.add newSymNode(argsParam)
|
||||||
|
result.typ = newType(tyPtr, objType.owner)
|
||||||
|
result.typ.rawAddSon(objType)
|
||||||
|
|
||||||
|
proc wrapProcForSpawn*(owner: PSym; n: PNode): PNode =
|
||||||
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
if n.kind notin nkCallKinds or not n.typ.isEmptyType:
|
||||||
|
localError(n.info, "'spawn' takes a call expression of type void")
|
||||||
|
return
|
||||||
|
var
|
||||||
|
threadParam = newSym(skParam, getIdent"thread", owner, n.info)
|
||||||
|
argsParam = newSym(skParam, getIdent"args", owner, n.info)
|
||||||
|
block:
|
||||||
|
let ptrType = getSysType(tyPointer)
|
||||||
|
threadParam.typ = ptrType
|
||||||
|
argsParam.typ = ptrType
|
||||||
|
argsParam.position = 1
|
||||||
|
var objType = createObj(owner, n.info)
|
||||||
|
let castExpr = createCastExpr(argsParam, objType)
|
||||||
|
|
||||||
|
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
|
||||||
|
block:
|
||||||
|
scratchObj.typ = objType
|
||||||
|
incl(scratchObj.flags, sfFromGeneric)
|
||||||
|
var varSectionB = newNodeI(nkVarSection, n.info)
|
||||||
|
varSectionB.addVar(scratchObj.newSymNode)
|
||||||
|
result.add varSectionB
|
||||||
|
|
||||||
|
var call = newNodeI(nkCall, n.info)
|
||||||
|
var fn = n.sons[0]
|
||||||
|
# templates and macros are in fact valid here due to the nature of
|
||||||
|
# the transformation:
|
||||||
|
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
|
||||||
|
skMethod, skConverter}):
|
||||||
|
# for indirect calls we pass the function pointer in the scratchObj
|
||||||
|
var argType = n[0].typ.skipTypes(abstractInst)
|
||||||
|
var field = newSym(skField, getIdent"fn", owner, n.info)
|
||||||
|
field.typ = argType
|
||||||
|
objType.addField(field)
|
||||||
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
|
||||||
|
fn = indirectAccess(castExpr, field, n.info)
|
||||||
|
elif fn.kind == nkSym and fn.sym.kind in {skClosureIterator, skIterator}:
|
||||||
|
localError(n.info, "iterator in spawn environment is not allowed")
|
||||||
|
elif fn.typ.callConv == ccClosure:
|
||||||
|
localError(n.info, "closure in spawn environment is not allowed")
|
||||||
|
|
||||||
|
call.add(fn)
|
||||||
|
var varSection = newNodeI(nkVarSection, n.info)
|
||||||
|
let formals = n[0].typ.n
|
||||||
|
let tmpName = getIdent(genPrefix)
|
||||||
|
for i in 1 .. <n.len:
|
||||||
|
# we pick n's type here, which hopefully is 'tyArray' and not
|
||||||
|
# 'tyOpenArray':
|
||||||
|
var argType = n[i].typ.skipTypes(abstractInst)
|
||||||
|
if argType.kind == tyVar:
|
||||||
|
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
|
||||||
|
elif containsTyRef(argType):
|
||||||
|
localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||||
|
|
||||||
|
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||||
|
var field = newSym(skField, fieldname, owner, n.info)
|
||||||
|
field.typ = argType
|
||||||
|
objType.addField(field)
|
||||||
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
||||||
|
|
||||||
|
var temp = newSym(skTemp, tmpName, owner, n.info)
|
||||||
|
temp.typ = argType
|
||||||
|
incl(temp.flags, sfFromGeneric)
|
||||||
|
|
||||||
|
var vpart = newNodeI(nkIdentDefs, n.info, 3)
|
||||||
|
vpart.sons[0] = newSymNode(temp)
|
||||||
|
vpart.sons[1] = ast.emptyNode
|
||||||
|
vpart.sons[2] = indirectAccess(castExpr, field, n.info)
|
||||||
|
varSection.add vpart
|
||||||
|
|
||||||
|
call.add(newSymNode(temp))
|
||||||
|
|
||||||
|
let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, call)
|
||||||
|
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
||||||
|
genAddrOf(scratchObj.newSymNode))
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
if result.typ != nil:
|
if result.typ != nil:
|
||||||
# XXX tyGenericInst here?
|
# XXX tyGenericInst here?
|
||||||
if result.typ.kind == tyVar: result = newDeref(result)
|
if result.typ.kind == tyVar: result = newDeref(result)
|
||||||
|
elif efWantStmt in flags:
|
||||||
|
result.typ = newTypeS(tyEmpty, c)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errExprXHasNoType,
|
localError(n.info, errExprXHasNoType,
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -1284,6 +1284,7 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
|
||||||
result = a
|
result = a
|
||||||
elif a.typ.isNil:
|
elif a.typ.isNil:
|
||||||
let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
|
let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
|
||||||
|
elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
|
||||||
else: {efDetermineType}
|
else: {efDetermineType}
|
||||||
result = c.semOperand(c, a, flags)
|
result = c.semOperand(c, a, flags)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ type
|
||||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||||
wAsmNoStackFrame,
|
wAsmNoStackFrame,
|
||||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked,
|
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard,
|
||||||
|
|
||||||
wAuto, wBool, wCatch, wChar, wClass,
|
wAuto, wBool, wCatch, wChar, wClass,
|
||||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||||
|
|
@ -146,6 +146,7 @@ const
|
||||||
"computedgoto", "injectstmt",
|
"computedgoto", "injectstmt",
|
||||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||||
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||||
|
"guard",
|
||||||
|
|
||||||
"auto", "bool", "catch", "char", "class",
|
"auto", "bool", "catch", "char", "class",
|
||||||
"const_cast", "default", "delete", "double",
|
"const_cast", "default", "delete", "double",
|
||||||
|
|
|
||||||
|
|
@ -722,10 +722,13 @@ proc alloc0(allocator: var TMemRegion, size: int): pointer =
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
|
|
||||||
proc dealloc(allocator: var TMemRegion, p: pointer) =
|
proc dealloc(allocator: var TMemRegion, p: pointer) =
|
||||||
|
sysAssert(p != nil, "dealloc 0")
|
||||||
var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
|
var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
|
||||||
sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 1")
|
sysAssert(x != nil, "dealloc 1")
|
||||||
|
sysAssert(isAccessible(allocator, x), "is not accessible")
|
||||||
|
sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 2")
|
||||||
rawDealloc(allocator, x)
|
rawDealloc(allocator, x)
|
||||||
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 2")
|
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
|
||||||
|
|
||||||
proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer =
|
proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer =
|
||||||
if newsize > 0:
|
if newsize > 0:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue