diff options
author | Araq <rumpf_a@web.de> | 2014-04-16 08:44:57 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-04-16 08:44:57 +0200 |
commit | 8e08ff559f4c03587c683b1bf2ef71f256af3824 (patch) | |
tree | 58b3814cc079243ab759ba80e1d7a7802fa0caab | |
parent | b961e47bfe519bf456a3e8a0dba3025a3c047b04 (diff) | |
download | Nim-8e08ff559f4c03587c683b1bf2ef71f256af3824.tar.gz |
first version of 'spawn'
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 3 | ||||
-rw-r--r-- | compiler/cgen.nim | 2 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 31 | ||||
-rw-r--r-- | compiler/lowerings.nim | 174 | ||||
-rw-r--r-- | compiler/semexprs.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 1 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 3 | ||||
-rw-r--r-- | lib/system/alloc.nim | 7 |
9 files changed, 188 insertions, 37 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 791b73685..e720d2bfa 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -559,7 +559,7 @@ type mFloat, mFloat32, mFloat64, mFloat128, mBool, mChar, mString, mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, - mVoidType, mPNimrodNode, mShared, mGuarded, + mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType, mNaN, mInf, mNegInf, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e346e1b53..9702fb25c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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) of mSlurp..mQuoteAst: 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) proc genConstExpr(p: BProc, n: PNode): PRope diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 683aed069..f64ebacfb 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -14,7 +14,7 @@ import options, intsets, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, 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: import tccgen diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 440468ac4..c5b9d0f00 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -141,12 +141,6 @@ type closureParam, state, resultSym: PSym # 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 = var n = newNodeI(nkRange, iter.info) addSon(n, newIntNode(nkIntLit, -1)) @@ -189,15 +183,6 @@ proc getEnvParam(routine: PSym): PSym = let hidden = lastSon(params) if hidden.kind == nkSym and hidden.sym.name.s == paramName: 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) = c.fn = iter @@ -273,22 +258,6 @@ proc addDep(e, d: PEnv, owner: PSym): PSym = rawAddSon(result.typ, d.obj) addField(e.obj, 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 = result = newNodeI(nkCall, a.info) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 2cf641d93..bee3427f4 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -12,7 +12,7 @@ const 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 = result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes( @@ -34,6 +34,11 @@ proc newAsgnStmt(le, ri: PNode): PNode = result.sons[0] = le 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 = assert n.kind == nkVarTuple let value = n.lastSon @@ -50,3 +55,170 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = result.add newAsgnStmt(newSymNode(temp), value) for i in 0 .. n.len-3: 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)) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6c1721bdd..652e1dd4b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -30,6 +30,8 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ != nil: # XXX tyGenericInst here? if result.typ.kind == tyVar: result = newDeref(result) + elif efWantStmt in flags: + result.typ = newTypeS(tyEmpty, c) else: localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 9d1585c56..6b85542d3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1284,6 +1284,7 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode = result = a elif a.typ.isNil: let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator} + elif formal.kind == tyStmt: {efDetermineType, efWantStmt} else: {efDetermineType} result = c.semOperand(c, a, flags) else: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 47ce89789..9a74f53fc 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -63,7 +63,7 @@ type wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt, wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, wAsmNoStackFrame, - wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, + wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wAuto, wBool, wCatch, wChar, wClass, wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, @@ -146,6 +146,7 @@ const "computedgoto", "injectstmt", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked", + "guard", "auto", "bool", "catch", "char", "class", "const_cast", "default", "delete", "double", diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 954485eb4..eaef6cd95 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -722,10 +722,13 @@ proc alloc0(allocator: var TMemRegion, size: int): pointer = zeroMem(result, size) proc dealloc(allocator: var TMemRegion, p: pointer) = + sysAssert(p != nil, "dealloc 0") 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) - sysAssert(not isAllocatedPtr(allocator, x), "dealloc 2") + sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3") proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer = if newsize > 0: |