first version of 'spawn'

This commit is contained in:
Araq 2014-04-16 08:44:57 +02:00
commit 8e08ff559f
9 changed files with 188 additions and 37 deletions

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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))

View file

@ -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}))

View file

@ -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:

View file

@ -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",

View file

@ -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: