diff options
author | Araq <rumpf_a@web.de> | 2014-02-25 01:21:00 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-02-25 01:21:00 +0100 |
commit | 20131c32af45905fcbfd64ce1fbdfa8e83ecee2d (patch) | |
tree | 24f2d9c91387ce4fabf400089440521c9b1fb034 | |
parent | 10768904eb65da1899d0d48cc1a2f3547af3bef0 (diff) | |
parent | 263cabd1c27977aa32c849ffb334984e8d476b97 (diff) | |
download | Nim-20131c32af45905fcbfd64ce1fbdfa8e83ecee2d.tar.gz |
Merge branch 'vm2_2' into devel
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/astalgo.nim | 10 | ||||
-rw-r--r-- | compiler/canonicalizer.nim | 288 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 1 | ||||
-rw-r--r-- | compiler/jsgen.nim | 1 | ||||
-rw-r--r-- | compiler/msgs.nim | 4 | ||||
-rw-r--r-- | compiler/renderer.nim | 2 | ||||
-rw-r--r-- | compiler/rodread.nim | 2 | ||||
-rw-r--r-- | compiler/sem.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | compiler/semfold.nim | 2 | ||||
-rw-r--r-- | compiler/semstmts.nim | 9 | ||||
-rw-r--r-- | compiler/types.nim | 2 | ||||
-rw-r--r-- | compiler/vm.nim | 967 | ||||
-rw-r--r-- | compiler/vmdef.nim | 23 | ||||
-rw-r--r-- | compiler/vmgen.nim | 174 | ||||
-rw-r--r-- | tests/macros/tmacro5.nim | 2 | ||||
-rw-r--r-- | tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim | 7 | ||||
-rw-r--r-- | tests/manyloc/keineschweine/dependencies/enet/enet.nim | 9 | ||||
-rw-r--r-- | tests/manyloc/keineschweine/dependencies/sfml/sfml.nim | 12 | ||||
-rw-r--r-- | todo.txt | 6 |
21 files changed, 966 insertions, 567 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index fe724f4dd..bd8bdb30b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -62,7 +62,7 @@ type nkTripleStrLit, # a triple string literal """ nkNilLit, # the nil literal # end of atoms - nkMetaNode, # difficult to explain; represents itself + nkMetaNode_Obsolete, # difficult to explain; represents itself # (used for macros) nkDotCall, # used to temporarily flag a nkCall node; # this is used @@ -1112,10 +1112,6 @@ proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = result.info = info result.typ = typ -proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode = - result = newNodeIT(nkMetaNode, info, typ) - result.add(tree) - var emptyParams = newNode(nkFormalParams) emptyParams.addSon(emptyNode) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 64c1b717c..cce2cc215 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -337,7 +337,10 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, appf(result, ",$N$1\"floatVal\": $2", [istr, toRope(n.floatVal.toStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: - appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) + if n.strVal.isNil: + appf(result, ",$N$1\"strVal\": null", [istr]) + else: + appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: appf(result, ",$N$1\"sym\": $2", [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)]) @@ -407,7 +410,10 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = appf(result, ",$N$1\"floatVal\": $2", [istr, toRope(n.floatVal.toStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: - appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) + if n.strVal.isNil: + appf(result, ",$N$1\"strVal\": null", [istr]) + else: + appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: appf(result, ",$N$1\"sym\": $2_$3", [istr, toRope(n.sym.name.s), toRope(n.sym.id)]) diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim new file mode 100644 index 000000000..fb5b3b9ce --- /dev/null +++ b/compiler/canonicalizer.nim @@ -0,0 +1,288 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the canonalization for the various caching mechanisms. + +import strutils, db_sqlite, md5 + +var db: TDbConn + +# We *hash* the relevant information into 128 bit hashes. This should be good enough +# to prevent any collisions. + +type + TUid = distinct MD5Digest + +# For name mangling we encode these hashes via a variant of base64 (called +# 'base64a') and prepend the *primary* identifier to ease the debugging pain. +# So a signature like: +# +# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) +# +# is mangled into: +# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA +# +# This is a good compromise between correctness and brevity. ;-) + +const + cb64 = [ + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", + "O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", + "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "_A", "_B"] + +proc toBase64a(s: cstring, len: int): string = + ## encodes `s` into base64 representation. After `lineLen` characters, a + ## `newline` is added. + var total = ((len + 2) div 3) * 4 + result = newStringOfCap(total) + var i = 0 + while i < s.len - 2: + let a = ord(s[i]) + let b = ord(s[i+1]) + let c = ord(s[i+2]) + result.add cb64[a shr 2] + result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] + result.add cb64[c and 0x3F] + inc(i, 3) + if i < s.len-1: + let a = ord(s[i]) + let b = ord(s[i+1]) + result.add cb64[a shr 2] + result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result.add cb64[((b and 0x0F) shl 2)] + elif i < s.len: + let a = ord(s[i]) + result.add cb64[a shr 2] + result.add cb64[(a and 3) shl 4] + +proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u)) + +proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) + +proc hashSym(c: var MD5Context, s: PSym) = + if sfAnon in s.flags or s.kind == skGenericParam: + c &= ":anon" + else: + var it = s.owner + while it != nil: + hashSym(c, it) + c &= "." + it = s.owner + c &= s.name.s + +proc hashTree(c: var MD5Context, n: PNode) = + if n == nil: + c &= "null" + return + var k = n.kind + md5Update(c, cast[cstring](addr(k)), 1) + # we really must not hash line information. 'n.typ' is debatable but + # shouldn't be necessary for now and avoids potential infinite recursions. + case n.kind + of nkEmpty, nkNilLit, nkType: discard + of nkIdent: + c &= n.ident.s + of nkSym: + hashSym(c, n.sym) + of nkCharLit..nkUInt64Lit: + var v = n.intVal + md5Update(c, cast[cstring](addr(v)), sizeof(v)) + of nkFloatLit..nkFloat64Lit: + var v = n.floatVal + md5Update(c, cast[cstring](addr(v)), sizeof(v)) + of nkStrLit..nkTripleStrLit: + c &= n.strVal + else: + for i in 0.. <n.len: hashTree(c, n.sons[i]) + +const + typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", + "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc", + "GenericInvokation", "GenericBody", "GenericInst", "GenericParam", + "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple", + "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc", + "pointer", "OpenArray[$1]", "string", "CString", "Forward", + "int", "int8", "int16", "int32", "int64", + "float", "float32", "float64", "float128", + "uint", "uint8", "uint16", "uint32", "uint64", + "bignum", "const ", + "!", "varargs[$1]", "iter[$1]", "Error Type", + "BuiltInTypeClass", "UserTypeClass", + "UserTypeClassInst", "CompositeTypeClass", + "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"] + +proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = + var t = typ + result = "" + if t == nil: return + if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags: + if t.kind == tyInt and isIntLit(t): + return t.sym.name.s & " literal(" & $t.n.intVal & ")" + return t.sym.name.s + case t.kind + of tyInt: + if not isIntLit(t) or prefer == preferExported: + result = typeToStr[t.kind] + else: + result = "int literal(" & $t.n.intVal & ")" + of tyGenericBody, tyGenericInst, tyGenericInvokation: + result = typeToString(t.sons[0]) & '[' + for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)): + if i > 1: add(result, ", ") + add(result, typeToString(t.sons[i])) + add(result, ']') + of tyTypeDesc: + if t.base.kind == tyNone: result = "typedesc" + else: result = "typedesc[" & typeToString(t.base) & "]" + of tyStatic: + internalAssert t.len > 0 + result = "static[" & typeToString(t.sons[0]) & "]" + of tyUserTypeClass: + internalAssert t.sym != nil and t.sym.owner != nil + return t.sym.owner.name.s + of tyBuiltInTypeClass: + result = case t.base.kind: + of tyVar: "var" + of tyRef: "ref" + of tyPtr: "ptr" + of tySequence: "seq" + of tyArray: "array" + of tySet: "set" + of tyRange: "range" + of tyDistinct: "distinct" + of tyProc: "proc" + of tyObject: "object" + of tyTuple: "tuple" + else: (internalAssert(false); "") + of tyUserTypeClassInst: + let body = t.base + result = body.sym.name.s & "[" + for i in countup(1, sonsLen(t) - 2): + if i > 1: add(result, ", ") + add(result, typeToString(t.sons[i])) + result.add "]" + of tyAnd: + result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) + of tyOr: + result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1]) + of tyNot: + result = "not " & typeToString(t.sons[0]) + of tyExpr: + internalAssert t.len == 0 + result = "expr" + of tyFromExpr, tyFieldAccessor: + result = renderTree(t.n) + of tyArray: + if t.sons[0].kind == tyRange: + result = "array[" & hashTree(t.sons[0].n) & ", " & + typeToString(t.sons[1]) & ']' + else: + result = "array[" & typeToString(t.sons[0]) & ", " & + typeToString(t.sons[1]) & ']' + of tyArrayConstr: + result = "Array constructor[" & hashTree(t.sons[0].n) & ", " & + typeToString(t.sons[1]) & ']' + of tySequence: + result = "seq[" & typeToString(t.sons[0]) & ']' + of tyOrdinal: + result = "ordinal[" & typeToString(t.sons[0]) & ']' + of tySet: + result = "set[" & typeToString(t.sons[0]) & ']' + of tyOpenArray: + result = "openarray[" & typeToString(t.sons[0]) & ']' + of tyDistinct: + result = "distinct " & typeToString(t.sons[0], preferName) + of tyTuple: + # we iterate over t.sons here, because t.n may be nil + result = "tuple[" + if t.n != nil: + assert(sonsLen(t.n) == sonsLen(t)) + for i in countup(0, sonsLen(t.n) - 1): + assert(t.n.sons[i].kind == nkSym) + add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i])) + if i < sonsLen(t.n) - 1: add(result, ", ") + else: + for i in countup(0, sonsLen(t) - 1): + add(result, typeToString(t.sons[i])) + if i < sonsLen(t) - 1: add(result, ", ") + add(result, ']') + of tyPtr, tyRef, tyVar, tyMutable, tyConst: + result = typeToStr[t.kind] & typeToString(t.sons[0]) + of tyRange: + result = "range " & hashTree(t.n) + if prefer != preferExported: + result.add("(" & typeToString(t.sons[0]) & ")") + of tyProc: + result = if tfIterator in t.flags: "iterator (" else: "proc (" + for i in countup(1, sonsLen(t) - 1): + add(result, typeToString(t.sons[i])) + if i < sonsLen(t) - 1: add(result, ", ") + add(result, ')') + if t.sons[0] != nil: add(result, ": " & typeToString(t.sons[0])) + var prag: string + if t.callConv != ccDefault: prag = CallingConvToStr[t.callConv] + else: prag = "" + if tfNoSideEffect in t.flags: + addSep(prag) + add(prag, "noSideEffect") + if tfThread in t.flags: + addSep(prag) + add(prag, "thread") + if len(prag) != 0: add(result, "{." & prag & ".}") + of tyVarargs, tyIter: + result = typeToStr[t.kind] % typeToString(t.sons[0]) + else: + result = typeToStr[t.kind] + if tfShared in t.flags: result = "shared " & result + if tfNotNil in t.flags: result.add(" not nil") + + +proc createDb() = + db.exec(sql""" + create table if not exists Module( + id integer primary key, + name varchar(256) not null, + fullpath varchar(256) not null, + interfHash varchar(256) not null, + fullHash varchar(256) not null, + + created timestamp not null default (DATETIME('now')), + );""") + + db.exec(sql""" + create table if not exists Symbol( + id integer primary key, + module integer not null, + name varchar(max) not null, + data varchar(max) not null, + created timestamp not null default (DATETIME('now')), + + foreign key (module) references module(id) + );""") + + db.exec(sql""" + create table if not exists Type( + id integer primary key, + module integer not null, + name varchar(max) not null, + data varchar(max) not null, + created timestamp not null default (DATETIME('now')), + + foreign key (module) references module(id) + );""") + + + #db.exec(sql""" + # --create unique index if not exists TsstNameIx on TestResult(name); + # """, []) + diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 27f7f4ba5..8cb423688 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1915,7 +1915,6 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = internalError(n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of nkClosure: genClosure(p, n, d) - of nkMetaNode: expr(p, n.sons[0], d) of nkEmpty: discard of nkWhileStmt: genWhileStmt(p, n) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c0fc4131a..a8a15f542 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1600,7 +1600,6 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = if lfNoDecl in s.loc.flags or s.magic != mNone: discard elif not p.g.generatedSyms.containsOrIncl(s.id): app(p.locals, genProc(p, s)) - of nkMetaNode: gen(p, n.sons[0], r) of nkType: r.res = genTypeInfo(p, n.typ) of nkStmtList, nkStmtListExpr: # this shows the distinction is nice for backends and should be kept diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b44ca2ff0..66763e7f5 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -67,7 +67,7 @@ type errAmbiguousCallXYZ, errWrongNumberOfArguments, errXCannotBePassedToProcVar, errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, - errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue, + errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, errInvalidOrderInArrayConstructor, errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, @@ -266,7 +266,7 @@ const errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", errImplOfXexpected: "implementation of \'$1\' expected", errNoSymbolToBorrowFromFound: "no symbol to borrow from found", - errDiscardValue: "value returned by statement has to be discarded", + errDiscardValueX: "value of type '$1' has to be discarded", errInvalidDiscard: "statement returns no value that can be discarded", errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", errCannotBindXTwice: "cannot bind parameter \'$1\' twice", diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 1afb5961e..509c815c1 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1268,7 +1268,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkBracketLe, "[") gcomma(g, n) put(g, tkBracketRi, "]") - of nkMetaNode: + of nkMetaNode_Obsolete: put(g, tkParLe, "(META|") gsub(g, n.sons[0]) put(g, tkParRi, ")") diff --git a/compiler/rodread.nim b/compiler/rodread.nim index b53135a95..036e6cc3c 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -890,7 +890,7 @@ proc loadStub*(s: PSym) = # deactivate the GC here because we do a deep recursion and generate no # garbage when restoring parts of the object graph anyway. - # Since we die with internal errors if this fails, so no try-finally is + # Since we die with internal errors if this fails, no try-finally is # necessary. GC_disable() rawLoadStub(s) diff --git a/compiler/sem.nim b/compiler/sem.nim index 09b2511f1..5ee46654e 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -220,7 +220,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = return nil result = fixupTypeAfterEval(c, result, e) - except: + except ERecoverableError: return nil proc semConstExpr(c: PContext, n: PNode): PNode = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c271911ab..538489490 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -641,9 +641,11 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = result = evalStaticExpr(c.module, call, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(call)) + else: result = fixupTypeAfterEval(c, result, n) else: result = evalConstExpr(c.module, call) if result.isNil: result = n + else: result = fixupTypeAfterEval(c, result, n) #if result != n: # echo "SUCCESS evaluated at compile time: ", call.renderTree @@ -653,6 +655,8 @@ proc semStaticExpr(c: PContext, n: PNode): PNode = if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode + else: + result = fixupTypeAfterEval(c, result, a) proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, flags: TExprFlags): PNode = diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 4740ddcb3..925a80832 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -537,7 +537,7 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode = if result.kind == nkExprColonExpr: result = result.sons[1] else: localError(n.info, errIndexOutOfBounds) - of nkBracket, nkMetaNode: + of nkBracket: if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)] else: localError(n.info, errIndexOutOfBounds) of nkStrLit..nkTripleStrLit: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6c4e29f29..c8d9e353a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -126,7 +126,7 @@ proc implicitlyDiscardable(n: PNode): bool = proc fixNilType(n: PNode) = if isAtom(n): if n.kind != nkNilLit and n.typ != nil: - localError(n.info, errDiscardValue) + localError(n.info, errDiscardValueX, n.typ.typeToString) elif n.kind in {nkStmtList, nkStmtListExpr}: n.kind = nkStmtList for it in n: fixNilType(it) @@ -155,7 +155,7 @@ proc discardCheck(c: PContext, result: PNode) = else: var n = result while n.kind in skipForDiscardable: n = n.lastSon - localError(n.info, errDiscardValue) + localError(n.info, errDiscardValueX, result.typ.typeToString) proc semIf(c: PContext, n: PNode): PNode = result = n @@ -332,6 +332,7 @@ proc checkNilable(v: PSym) = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode result = copyNode(n) + var hasCompileTime = false for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) @@ -411,7 +412,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = v.typ = tup.sons[j] b.sons[j] = newSymNode(v) checkNilable(v) - + if sfCompileTime in v.flags: hasCompileTime = true + if hasCompileTime: vm.setupCompileTimeVar(c.module, result) + proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/types.nim b/compiler/types.nim index d7148f110..e6178f446 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -463,7 +463,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyAnd: result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) of tyOr: - result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) + result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1]) of tyNot: result = "not " & typeToString(t.sons[0]) of tyExpr: diff --git a/compiler/vm.nim b/compiler/vm.nim index 0929e072b..6277b2dc6 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -8,7 +8,7 @@ # ## This file implements the new evaluation engine for Nimrod code. -## An instruction is 1-2 int32s in memory, it is a register based VM. +## An instruction is 1-3 int32s in memory, it is a register based VM. import ast except getstr @@ -23,10 +23,22 @@ when hasFFI: import evalffi type + TRegisterKind = enum + rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr + TRegister = object # with a custom mark proc, we could use the same + # data representation as LuaJit (tagged NaNs). + case kind: TRegisterKind + of rkNone: nil + of rkInt: intVal: BiggestInt + of rkFloat: floatVal: BiggestFloat + of rkNode: node: PNode + of rkRegisterAddr: regAddr: ptr TRegister + of rkNodeAddr: nodeAddr: ptr PNode + PStackFrame* = ref TStackFrame TStackFrame* = object prc: PSym # current prc; proc that is evaluated - slots: TNodeSeq # parameters passed to the proc + locals; + slots: seq[TRegister] # parameters passed to the proc + locals; # parameters come first next: PStackFrame # for stacking comesFrom: int @@ -63,24 +75,9 @@ proc bailOut(c: PCtx; tos: PStackFrame) = when not defined(nimComputedGoto): {.pragma: computedGoto.} -proc myreset(n: PNode) = +proc myreset(n: var TRegister) = when defined(system.reset): - var oldInfo = n.info - reset(n[]) - n.info = oldInfo - -proc skipMeta(n: PNode): PNode = (if n.kind != nkMetaNode: n else: n.sons[0]) - -proc setMeta(n, child: PNode) = - assert n.kind == nkMetaNode - let child = child.skipMeta - if n.sons.isNil: n.sons = @[child] - else: n.sons[0] = child - -proc uast(n: PNode): PNode {.inline.} = - # "underlying ast" - assert n.kind == nkMetaNode - n.sons[0] + reset(n) template ensureKind(k: expr) {.immediate, dirty.} = if regs[ra].kind != k: @@ -112,23 +109,29 @@ template decodeBx(k: expr) {.immediate, dirty.} = template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b) # XXX fix minor 'shallowCopy' overloading bug in compiler -proc moveConst(x, y: PNode) = +template createStrKeepNode(x) = + if x.node.isNil: + x.node = newNode(nkStrLit) + elif x.node.kind == nkNilLit: + system.reset(x.node[]) + x.node.kind = nkStrLit + else: + assert x.node.kind in {nkStrLit..nkTripleStrLit} + +template createStr(x) = + x.node = newNode(nkStrLit) + +proc moveConst(x: var TRegister, y: TRegister) = if x.kind != y.kind: myreset(x) x.kind = y.kind - x.typ = y.typ case x.kind - of nkCharLit..nkInt64Lit: x.intVal = y.intVal - of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal - of nkStrLit..nkTripleStrLit: move(x.strVal, y.strVal) - of nkIdent: x.ident = y.ident - of nkSym: x.sym = y.sym - of nkMetaNode: - if x.sons.isNil: x.sons = @[y.sons[0]] - else: x.sons[0] = y.sons[0] - else: - if x.kind notin {nkEmpty..nkNilLit}: - move(x.sons, y.sons) + of rkNone: discard + of rkInt: x.intVal = y.intVal + of rkFloat: x.floatVal = y.floatVal + of rkNode: x.node = y.node + of rkRegisterAddr: x.regAddr = y.regAddr + of rkNodeAddr: x.nodeAddr = y.nodeAddr # this seems to be the best way to model the reference semantics # of PNimrodNode: @@ -155,29 +158,54 @@ proc copyValue(src: PNode): PNode = for i in countup(0, sonsLen(src) - 1): result.sons[i] = copyValue(src.sons[i]) -proc asgnComplex(x, y: PNode) = +proc asgnComplex(x: var TRegister, y: TRegister) = if x.kind != y.kind: myreset(x) x.kind = y.kind - x.typ = y.typ case x.kind - of nkCharLit..nkInt64Lit: x.intVal = y.intVal - of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal - of nkStrLit..nkTripleStrLit: x.strVal = y.strVal - of nkIdent: x.ident = y.ident - of nkSym: x.sym = y.sym - of nkMetaNode: - if x.sons.isNil: x.sons = @[y.sons[0]] - else: x.sons[0] = y.sons[0] + of rkNone: discard + of rkInt: x.intVal = y.intVal + of rkFloat: x.floatVal = y.floatVal + of rkNode: x.node = copyValue(y.node) + of rkRegisterAddr: x.regAddr = y.regAddr + of rkNodeAddr: x.nodeAddr = y.nodeAddr + +proc putIntoNode(n: PNode; x: TRegister) = + case x.kind + of rkNone: discard + of rkInt: n.intVal = x.intVal + of rkFloat: n.floatVal = x.floatVal + of rkNode: n[] = x.node[] + of rkRegisterAddr: putIntoNode(n, x.regAddr[]) + of rkNodeAddr: n[] = x.nodeAddr[][] + +proc putIntoReg(dest: var TRegister; n: PNode) = + case n.kind + of nkStrLit..nkTripleStrLit: + dest.kind = rkNode + createStr(dest) + dest.node.strVal = n.strVal + of nkCharLit..nkUInt64Lit: + dest.kind = rkInt + dest.intVal = n.intVal + of nkFloatLit..nkFloat128Lit: + dest.kind = rkFloat + dest.floatVal = n.floatVal else: - if x.kind notin {nkEmpty..nkNilLit}: - let y = y.copyValue - for i in countup(0, sonsLen(y) - 1): - if i < x.len: x.sons[i] = y.sons[i] - else: addSon(x, y.sons[i]) + dest.kind = rkNode + dest.node = n + +proc regToNode(x: TRegister): PNode = + case x.kind + of rkNone: result = newNode(nkEmpty) + of rkInt: result = newNode(nkIntLit); result.intVal = x.intVal + of rkFloat: result = newNode(nkFloatLit); result.floatVal = x.floatVal + of rkNode: result = x.node + of rkRegisterAddr: result = regToNode(x.regAddr[]) + of rkNodeAddr: result = x.nodeAddr[] template getstr(a: expr): expr = - (if a.kind in {nkStrLit..nkTripleStrLit}: a.strVal else: $chr(int(a.intVal))) + (if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal))) proc pushSafePoint(f: PStackFrame; pc: int) = if f.safePoints.isNil: f.safePoints = @[] @@ -185,7 +213,7 @@ proc pushSafePoint(f: PStackFrame; pc: int) = proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop() -proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int = +proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TRegister]): int = let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs) var f = tos while true: @@ -227,50 +255,65 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = return pc return -1 -proc opConv*(dest, src: PNode, typ: PType): bool = - if typ.kind == tyString: - if dest.kind != nkStrLit: +proc opConv*(dest: var TRegister, src: TRegister, desttyp, srctyp: PType): bool = + if desttyp.kind == tyString: + if dest.kind != rkNode: myreset(dest) - dest.kind = nkStrLit - case src.typ.skipTypes(abstractRange).kind - of tyEnum: - dest.strVal = ordinalValToString(src) - of tyInt..tyInt64, tyUInt..tyUInt64: - dest.strVal = $src.intVal + dest.kind = rkNode + dest.node = newNode(nkStrLit) + let styp = srctyp.skipTypes(abstractRange) + case styp.kind + of tyEnum: + let n = styp.n + let x = src.intVal.int + if x <% n.len and (let f = n.sons[x].sym; f.position == x): + dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal + else: + for i in 0.. <n.len: + if n.sons[i].kind != nkSym: internalError("opConv for enum") + let f = n.sons[i].sym + if f.position == x: + dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal + return + internalError("opConv for enum") + of tyInt..tyInt64: + dest.node.strVal = $src.intVal + of tyUInt..tyUInt64: + dest.node.strVal = $uint64(src.intVal) of tyBool: - dest.strVal = if src.intVal == 0: "false" else: "true" + dest.node.strVal = if src.intVal == 0: "false" else: "true" of tyFloat..tyFloat128: - dest.strVal = $src.floatVal + dest.node.strVal = $src.floatVal of tyString, tyCString: - dest.strVal = src.strVal + dest.node.strVal = src.node.strVal of tyChar: - dest.strVal = $chr(src.intVal) + dest.node.strVal = $chr(src.intVal) else: - internalError("cannot convert to string " & typ.typeToString) + internalError("cannot convert to string " & desttyp.typeToString) else: - case skipTypes(typ, abstractRange).kind + case skipTypes(desttyp, abstractRange).kind of tyInt..tyInt64: - if dest.kind != nkIntLit: - myreset(dest); dest.kind = nkIntLit - case skipTypes(src.typ, abstractRange).kind + if dest.kind != rkInt: + myreset(dest); dest.kind = rkInt + case skipTypes(srctyp, abstractRange).kind of tyFloat..tyFloat64: dest.intVal = system.toInt(src.floatVal) else: dest.intVal = src.intVal - if dest.intVal < firstOrd(typ) or dest.intVal > lastOrd(typ): + if dest.intVal < firstOrd(desttyp) or dest.intVal > lastOrd(desttyp): return true of tyUInt..tyUInt64: - if dest.kind != nkIntLit: - myreset(dest); dest.kind = nkIntLit - case skipTypes(src.typ, abstractRange).kind + if dest.kind != rkInt: + myreset(dest); dest.kind = rkInt + case skipTypes(srctyp, abstractRange).kind of tyFloat..tyFloat64: dest.intVal = system.toInt(src.floatVal) else: - dest.intVal = src.intVal and ((1 shl typ.size)-1) + dest.intVal = src.intVal and ((1 shl desttyp.size)-1) of tyFloat..tyFloat64: - if dest.kind != nkFloatLit: - myreset(dest); dest.kind = nkFloatLit - case skipTypes(src.typ, abstractRange).kind + if dest.kind != rkFloat: + myreset(dest); dest.kind = rkFloat + case skipTypes(srctyp, abstractRange).kind of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar: dest.floatVal = toFloat(src.intVal.int) else: @@ -282,23 +325,19 @@ proc compile(c: PCtx, s: PSym): int = result = vmgen.genProc(c, s) #c.echoCode -proc regsContents(regs: TNodeSeq) = - for i in 0.. <regs.len: - echo "Register ", i - #debug regs[i] - -proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = +proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister = var pc = start var tos = tos - var regs: TNodeSeq # alias to tos.slots for performance + var regs: seq[TRegister] # alias to tos.slots for performance move(regs, tos.slots) #echo "NEW RUN ------------------------" while true: #{.computedGoto.} let instr = c.code[pc] let ra = instr.regA - #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra - #message(c.debug[pc], warnUser, "gah") + #if c.traceActive: + # echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra + # message(c.debug[pc], warnUser, "Trace") case instr.opcode of opcEof: return regs[ra] of opcRet: @@ -318,325 +357,333 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = of opcYldYoid: assert false of opcYldVal: assert false of opcAsgnInt: - decodeB(nkIntLit) + decodeB(rkInt) regs[ra].intVal = regs[rb].intVal of opcAsgnStr: - if regs[instr.regB].kind == nkNilLit: - decodeB(nkNilLit) - else: - decodeB(nkStrLit) - regs[ra].strVal = regs[rb].strVal + decodeB(rkNode) + createStrKeepNode regs[ra] + regs[ra].node.strVal = regs[rb].node.strVal of opcAsgnFloat: - decodeB(nkFloatLit) + decodeB(rkFloat) regs[ra].floatVal = regs[rb].floatVal of opcAsgnComplex: asgnComplex(regs[ra], regs[instr.regB]) of opcAsgnRef: asgnRef(regs[ra], regs[instr.regB]) - of opcWrGlobalRef: - asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra]) - of opcWrGlobal: - asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra]) - of opcLdArr, opcLdArrRef: - # a = b[c] + of opcRegToNode: + decodeB(rkNode) + putIntoNode(regs[ra].node, regs[rb]) + of opcNodeToReg: + let ra = instr.regA let rb = instr.regB - let rc = instr.regC + assert regs[rb].kind == rkNode + let nb = regs[rb].node + case nb.kind + of nkCharLit..nkInt64Lit: + ensureKind(rkInt) + regs[ra].intVal = nb.intVal + of nkFloatLit..nkFloat64Lit: + ensureKind(rkFloat) + regs[ra].floatVal = nb.floatVal + else: + ensureKind(rkNode) + regs[ra].node = nb + of opcLdArr: + # a = b[c] + decodeBC(rkNode) if regs[rc].intVal > high(int): stackTrace(c, tos, pc, errIndexOutOfBounds) let idx = regs[rc].intVal.int # XXX what if the array is not 0-based? -> codegen should insert a sub - assert regs[rb].kind != nkMetaNode - let src = regs[rb] + let src = regs[rb].node if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len: - if instr.opcode == opcLdArrRef and false: - # XXX activate when seqs are fixed - asgnRef(regs[ra], src.sons[idx]) - else: - asgnComplex(regs[ra], src.sons[idx]) + regs[ra].node = src.sons[idx] else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcLdStrIdx: - decodeBC(nkIntLit) + decodeBC(rkInt) let idx = regs[rc].intVal.int - if idx <=% regs[rb].strVal.len: - regs[ra].intVal = regs[rb].strVal[idx].ord + if idx <=% regs[rb].node.strVal.len: + regs[ra].intVal = regs[rb].node.strVal[idx].ord else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcWrArr: # a[b] = c - let rb = instr.regB - let rc = instr.regC - let idx = regs[rb].intVal.int - if idx <% regs[ra].len: - asgnComplex(regs[ra].sons[idx], regs[rc]) - else: - stackTrace(c, tos, pc, errIndexOutOfBounds) - of opcWrArrRef: - let rb = instr.regB - let rc = instr.regC + decodeBC(rkNode) let idx = regs[rb].intVal.int - if idx <% regs[ra].len: - asgnRef(regs[ra].sons[idx], regs[rc]) + if idx <% regs[ra].node.len: + putIntoNode(regs[ra].node.sons[idx], regs[rc]) else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcLdObj: # a = b.c - let rb = instr.regB - let rc = instr.regC - #Message(c.debug[pc], warnUser, $regs[rb].safeLen & " " & $rc) - asgnComplex(regs[ra], regs[rb].sons[rc]) - of opcLdObjRef: - # a = b.c - let rb = instr.regB - let rc = instr.regC - # XXX activate when seqs are fixed - asgnComplex(regs[ra], regs[rb].sons[rc]) - #asgnRef(regs[ra], regs[rb].sons[rc]) + decodeBC(rkNode) + let src = regs[rb].node + if src.kind notin {nkEmpty..nkNilLit}: + regs[ra].node = src.sons[rc] + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcWrObj: # a.b = c - let rb = instr.regB - let rc = instr.regC - #if regs[ra].isNil or regs[ra].sons.isNil or rb >= len(regs[ra]): - # debug regs[ra] - # debug regs[rc] - # echo "RB ", rb - # internalError(c.debug[pc], "argl") - asgnComplex(regs[ra].sons[rb], regs[rc]) - of opcWrObjRef: - let rb = instr.regB - let rc = instr.regC - asgnRef(regs[ra].sons[rb], regs[rc]) + decodeBC(rkNode) + putIntoNode(regs[ra].node.sons[rb], regs[rc]) of opcWrStrIdx: - decodeBC(nkStrLit) + decodeBC(rkNode) let idx = regs[rb].intVal.int - if idx <% regs[ra].strVal.len: - regs[ra].strVal[idx] = chr(regs[rc].intVal) + if idx <% regs[ra].node.strVal.len: + regs[ra].node.strVal[idx] = chr(regs[rc].intVal) else: stackTrace(c, tos, pc, errIndexOutOfBounds) - of opcAddr: - decodeB(nkRefTy) - if regs[ra].len == 0: regs[ra].add regs[rb] - else: regs[ra].sons[0] = regs[rb] - of opcDeref: + of opcAddrReg: + decodeB(rkRegisterAddr) + regs[ra].regAddr = addr(regs[rb]) + of opcAddrNode: + decodeB(rkNodeAddr) + regs[ra].nodeAddr = addr(regs[rb].node) + of opcLdDeref: # a = b[] + let ra = instr.regA let rb = instr.regB - if regs[rb].kind == nkNilLit: - stackTrace(c, tos, pc, errNilAccess) - assert regs[rb].kind == nkRefTy - # XXX this is not correct - regs[ra] = regs[rb].sons[0] + case regs[rb].kind + of rkNodeAddr: + ensureKind(rkNode) + regs[ra].node = regs[rb].nodeAddr[] + of rkRegisterAddr: + ensureKind(regs[rb].regAddr.kind) + regs[ra] = regs[rb].regAddr[] + of rkNode: + if regs[rb].node.kind == nkNilLit: + stackTrace(c, tos, pc, errNilAccess) + assert regs[rb].node.kind == nkRefTy + regs[ra].node = regs[rb].node.sons[0] + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) + of opcWrDeref: + # a[] = b + decodeBC(rkNode) + putIntoNode(regs[ra].node, regs[rb]) of opcAddInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal + regs[rc].intVal of opcAddImmInt: - decodeBImm(nkIntLit) + decodeBImm(rkInt) regs[ra].intVal = regs[rb].intVal + imm of opcSubInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal - regs[rc].intVal of opcSubImmInt: - decodeBImm(nkIntLit) + decodeBImm(rkInt) regs[ra].intVal = regs[rb].intVal - imm of opcLenSeq: - decodeBImm(nkIntLit) + decodeBImm(rkInt) #assert regs[rb].kind == nkBracket # also used by mNLen: - regs[ra].intVal = regs[rb].skipMeta.safeLen - imm + regs[ra].intVal = regs[rb].node.safeLen - imm of opcLenStr: - decodeBImm(nkIntLit) - if regs[rb].kind == nkNilLit: - stackTrace(c, tos, pc, errNilAccess) - else: - assert regs[rb].kind in {nkStrLit..nkTripleStrLit} - regs[ra].intVal = regs[rb].strVal.len - imm + decodeBImm(rkInt) + assert regs[rb].kind == rkNode + regs[ra].intVal = regs[rb].node.strVal.len - imm of opcIncl: - decodeB(nkCurly) - if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb])) + decodeB(rkNode) + let b = regs[rb].regToNode + if not inSet(regs[ra].node, b): + addSon(regs[ra].node, copyTree(b)) of opcInclRange: - decodeBC(nkCurly) + decodeBC(rkNode) var r = newNode(nkRange) - r.add regs[rb] - r.add regs[rc] - addSon(regs[ra], r.copyTree) + r.add regs[rb].regToNode + r.add regs[rc].regToNode + addSon(regs[ra].node, r.copyTree) of opcExcl: - decodeB(nkCurly) - var b = newNodeIT(nkCurly, regs[rb].info, regs[rb].typ) - addSon(b, regs[rb]) - var r = diffSets(regs[ra], b) - discardSons(regs[ra]) - for i in countup(0, sonsLen(r) - 1): addSon(regs[ra], r.sons[i]) + decodeB(rkNode) + var b = newNodeIT(nkCurly, regs[rb].node.info, regs[rb].node.typ) + addSon(b, regs[rb].regToNode) + var r = diffSets(regs[ra].node, b) + discardSons(regs[ra].node) + for i in countup(0, sonsLen(r) - 1): addSon(regs[ra].node, r.sons[i]) of opcCard: - decodeB(nkIntLit) - regs[ra].intVal = nimsets.cardSet(regs[rb]) + decodeB(rkInt) + regs[ra].intVal = nimsets.cardSet(regs[rb].node) of opcMulInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal * regs[rc].intVal of opcDivInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal div regs[rc].intVal of opcModInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal of opcAddFloat: - decodeBC(nkFloatLit) + decodeBC(rkFloat) regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal of opcSubFloat: - decodeBC(nkFloatLit) + decodeBC(rkFloat) regs[ra].floatVal = regs[rb].floatVal - regs[rc].floatVal of opcMulFloat: - decodeBC(nkFloatLit) + decodeBC(rkFloat) regs[ra].floatVal = regs[rb].floatVal * regs[rc].floatVal of opcDivFloat: - decodeBC(nkFloatLit) + decodeBC(rkFloat) regs[ra].floatVal = regs[rb].floatVal / regs[rc].floatVal of opcShrInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal shr regs[rc].intVal of opcShlInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal of opcBitandInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal and regs[rc].intVal of opcBitorInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal or regs[rc].intVal of opcBitxorInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal xor regs[rc].intVal of opcAddu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal +% regs[rc].intVal of opcSubu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal of opcMulu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal of opcDivu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal /% regs[rc].intVal of opcModu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal %% regs[rc].intVal of opcEqInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal == regs[rc].intVal) of opcLeInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal <= regs[rc].intVal) of opcLtInt: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal < regs[rc].intVal) of opcEqFloat: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].floatVal == regs[rc].floatVal) of opcLeFloat: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].floatVal <= regs[rc].floatVal) of opcLtFloat: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].floatVal < regs[rc].floatVal) of opcLeu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal <=% regs[rc].intVal) of opcLtu: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal) of opcEqRef: - decodeBC(nkIntLit) - regs[ra].intVal = ord((regs[rb].kind == nkNilLit and - regs[rc].kind == nkNilLit) or - regs[rb].sons == regs[rc].sons) + decodeBC(rkInt) + regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and + regs[rc].node.kind == nkNilLit) or + regs[rb].node == regs[rc].node) of opcEqNimrodNode: - decodeBC(nkIntLit) - regs[ra].intVal = ord(regs[rb].skipMeta == regs[rc].skipMeta) + decodeBC(rkInt) + regs[ra].intVal = ord(regs[rb].node == regs[rc].node) of opcXor: - decodeBC(nkIntLit) + decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal) of opcNot: - decodeB(nkIntLit) - assert regs[rb].kind == nkIntLit + decodeB(rkInt) + assert regs[rb].kind == rkInt regs[ra].intVal = 1 - regs[rb].intVal of opcUnaryMinusInt: - decodeB(nkIntLit) - assert regs[rb].kind == nkIntLit + decodeB(rkInt) + assert regs[rb].kind == rkInt regs[ra].intVal = -regs[rb].intVal of opcUnaryMinusFloat: - decodeB(nkFloatLit) - assert regs[rb].kind == nkFloatLit + decodeB(rkFloat) + assert regs[rb].kind == rkFloat regs[ra].floatVal = -regs[rb].floatVal of opcBitnotInt: - decodeB(nkIntLit) - assert regs[rb].kind == nkIntLit + decodeB(rkInt) + assert regs[rb].kind == rkInt regs[ra].intVal = not regs[rb].intVal of opcEqStr: - decodeBC(nkIntLit) - regs[ra].intVal = ord(regs[rb].strVal == regs[rc].strVal) + decodeBC(rkInt) + regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal) of opcLeStr: - decodeBC(nkIntLit) - regs[ra].intVal = ord(regs[rb].strVal <= regs[rc].strVal) + decodeBC(rkInt) + regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal) of opcLtStr: - decodeBC(nkIntLit) - regs[ra].intVal = ord(regs[rb].strVal < regs[rc].strVal) + decodeBC(rkInt) + regs[ra].intVal = ord(regs[rb].node.strVal < regs[rc].node.strVal) of opcLeSet: - decodeBC(nkIntLit) - regs[ra].intVal = ord(containsSets(regs[rb], regs[rc])) + decodeBC(rkInt) + regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node)) of opcEqSet: - decodeBC(nkIntLit) - regs[ra].intVal = ord(equalSets(regs[rb], regs[rc])) + decodeBC(rkInt) + regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node)) of opcLtSet: - decodeBC(nkIntLit) - let a = regs[rb] - let b = regs[rc] + decodeBC(rkInt) + let a = regs[rb].node + let b = regs[rc].node regs[ra].intVal = ord(containsSets(a, b) and not equalSets(a, b)) of opcMulSet: - decodeBC(nkCurly) - move(regs[ra].sons, nimsets.intersectSets(regs[rb], regs[rc]).sons) + decodeBC(rkNode) + move(regs[ra].node.sons, + nimsets.intersectSets(regs[rb].node, regs[rc].node).sons) of opcPlusSet: - decodeBC(nkCurly) - move(regs[ra].sons, nimsets.unionSets(regs[rb], regs[rc]).sons) + decodeBC(rkNode) + move(regs[ra].node.sons, + nimsets.unionSets(regs[rb].node, regs[rc].node).sons) of opcMinusSet: - decodeBC(nkCurly) - move(regs[ra].sons, nimsets.diffSets(regs[rb], regs[rc]).sons) + decodeBC(rkNode) + move(regs[ra].node.sons, + nimsets.diffSets(regs[rb].node, regs[rc].node).sons) of opcSymdiffSet: - decodeBC(nkCurly) - move(regs[ra].sons, nimsets.symdiffSets(regs[rb], regs[rc]).sons) + decodeBC(rkNode) + move(regs[ra].node.sons, + nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons) of opcConcatStr: - decodeBC(nkStrLit) - regs[ra].strVal = getstr(regs[rb]) + decodeBC(rkNode) + createStr regs[ra] + regs[ra].node.strVal = getstr(regs[rb]) for i in rb+1..rb+rc-1: - regs[ra].strVal.add getstr(regs[i]) + regs[ra].node.strVal.add getstr(regs[i]) of opcAddStrCh: - decodeB(nkStrLit) - regs[ra].strVal.add(regs[rb].intVal.chr) + decodeB(rkNode) + createStrKeepNode regs[ra] + regs[ra].node.strVal.add(regs[rb].intVal.chr) of opcAddStrStr: - decodeB(nkStrLit) - regs[ra].strVal.add(regs[rb].strVal) + decodeB(rkNode) + createStrKeepNode regs[ra] + regs[ra].node.strVal.add(regs[rb].node.strVal) of opcAddSeqElem: - decodeB(nkBracket) - regs[ra].add(copyTree(regs[rb])) + decodeB(rkNode) + if regs[ra].node.kind == nkBracket: + regs[ra].node.add(copyTree(regs[rb].regToNode)) + else: + stackTrace(c, tos, pc, errNilAccess) of opcEcho: let rb = instr.regB for i in ra..ra+rb-1: - #if regs[i].kind != nkStrLit: debug regs[i] - write(stdout, regs[i].strVal) + #if regs[i].kind != rkNode: debug regs[i] + write(stdout, regs[i].node.strVal) writeln(stdout, "") of opcContainsSet: - decodeBC(nkIntLit) - regs[ra].intVal = ord(inSet(regs[rb], regs[rc])) + decodeBC(rkInt) + regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) of opcSubStr: - decodeBC(nkStrLit) + decodeBC(rkNode) inc pc assert c.code[pc].opcode == opcSubStr let rd = c.code[pc].regA - regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int, - regs[rd].intVal.int) + createStr regs[ra] + regs[ra].node.strVal = substr(regs[rb].node.strVal, + regs[rc].intVal.int, regs[rd].intVal.int) of opcRangeChck: let rb = instr.regB let rc = instr.regC - if not (leValueConv(regs[rb], regs[ra]) and - leValueConv(regs[ra], regs[rc])): + if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and + leValueConv(regs[ra].regToNode, regs[rc].regToNode)): stackTrace(c, tos, pc, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [ "unknown type" , "unknown type"]) @@ -644,8 +691,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = # dest = call regStart, n; where regStart = fn, arg1, ... let rb = instr.regB let rc = instr.regC - let isClosure = regs[rb].kind == nkPar - let prc = if not isClosure: regs[rb].sym else: regs[rb].sons[0].sym + let bb = regs[rb].node + let isClosure = bb.kind == nkPar + let prc = if not isClosure: bb.sym else: bb.sons[0].sym if sfImportc in prc.flags: if allowFFI notin c.features: globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI") @@ -659,7 +707,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = rb+1, rc-1, c.debug[pc]) if newValue.kind != nkEmpty: assert instr.opcode == opcIndCallAsgn - asgnRef(regs[ra], newValue) + putIntoReg(regs[ra], newValue) else: globalError(c.debug[pc], errGenerated, "VM not built with FFI support") elif prc.kind != skTemplate: @@ -668,15 +716,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) newSeq(newFrame.slots, prc.offset) if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro: - newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info) - # pass every parameter by var (the language definition allows this): + putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info)) for i in 1 .. rc-1: newFrame.slots[i] = regs[rb+i] if isClosure: - newFrame.slots[rc] = regs[rb].sons[1] + newFrame.slots[rc].kind = rkNode + newFrame.slots[rc].node = regs[rb].node.sons[1] # allocate the temporaries: - for i in rc+ord(isClosure) .. <prc.offset: - newFrame.slots[i] = newNode(nkEmpty) + #for i in rc+ord(isClosure) .. <prc.offset: + # newFrame.slots[i] = newNode(nkEmpty) tos = newFrame move(regs, newFrame.slots) # -1 for the following 'inc pc' @@ -689,10 +737,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = c.module var macroCall = newNodeI(nkCall, c.debug[pc]) macroCall.add(newSymNode(prc)) - for i in 1 .. rc-1: macroCall.add(regs[rb+i].skipMeta) + for i in 1 .. rc-1: macroCall.add(regs[rb+i].regToNode) let a = evalTemplate(macroCall, prc, genSymOwner) - ensureKind(nkMetaNode) - setMeta(regs[ra], a) + ensureKind(rkNode) + regs[ra].node = a of opcTJmp: # jump Bx if A != 0 let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' @@ -712,7 +760,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = let branch = c.constants[instr.regBx-wordExcess] var cond = false for j in countup(0, sonsLen(branch) - 2): - if overlap(regs[ra], branch.sons[j]): + if overlap(regs[ra].regToNode, branch.sons[j]): cond = true break assert c.code[pc+1].opcode == opcFJmp @@ -741,7 +789,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = bailOut(c, tos) return of opcRaise: - let raised = regs[ra] + let raised = regs[ra].node c.currentExceptionA = raised c.exceptionInstr = pc # -1 because of the following 'inc' @@ -750,319 +798,345 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = bailOut(c, tos) return of opcNew: + ensureKind(rkNode) let typ = c.types[instr.regBx - wordExcess] - regs[ra] = getNullValue(typ, regs[ra].info) - regs[ra].flags.incl nfIsRef + regs[ra].node = getNullValue(typ, c.debug[pc]) + regs[ra].node.flags.incl nfIsRef of opcNewSeq: let typ = c.types[instr.regBx - wordExcess] inc pc - ensureKind(nkBracket) + ensureKind(rkNode) let instr2 = c.code[pc] let count = regs[instr2.regA].intVal.int - regs[ra].typ = typ - newSeq(regs[ra].sons, count) + regs[ra].node = newNodeI(nkBracket, c.debug[pc]) + regs[ra].node.typ = typ + newSeq(regs[ra].node.sons, count) for i in 0 .. <count: - regs[ra].sons[i] = getNullValue(typ.sons[0], regs[ra].info) + regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc]) of opcNewStr: - decodeB(nkStrLit) - regs[ra].strVal = newString(regs[rb].intVal.int) + decodeB(rkNode) + regs[ra].node = newNodeI(nkStrLit, c.debug[pc]) + regs[ra].node.strVal = newString(regs[rb].intVal.int) of opcLdImmInt: # dest = immediate value - decodeBx(nkIntLit) + decodeBx(rkInt) regs[ra].intVal = rbx of opcLdNull: + ensureKind(rkNode) + let typ = c.types[instr.regBx - wordExcess] + regs[ra].node = getNullValue(typ, c.debug[pc]) + # opcLdNull really is the gist of the VM's problems: should it load + # a fresh null to regs[ra].node or to regs[ra].node[]? This really + # depends on whether regs[ra] represents the variable itself or wether + # it holds the indirection! Due to the way registers are re-used we cannot + # say for sure here! --> The codegen has to deal with it + # via 'genAsgnPatch'. + of opcLdNullReg: let typ = c.types[instr.regBx - wordExcess] - regs[ra] = getNullValue(typ, c.debug[pc]) + if typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}).kind in { + tyFloat..tyFloat128}: + ensureKind(rkFloat) + regs[ra].floatVal = 0.0 + else: + ensureKind(rkInt) + regs[ra].intVal = 0 of opcLdConst: let rb = instr.regBx - wordExcess - if regs[ra].isNil: - regs[ra] = copyTree(c.constants.sons[rb]) + let cnst = c.constants.sons[rb] + if fitsRegister(cnst.typ): + putIntoReg(regs[ra], cnst) else: - moveConst(regs[ra], c.constants.sons[rb]) + ensureKind(rkNode) + regs[ra].node = cnst of opcAsgnConst: let rb = instr.regBx - wordExcess - if regs[ra].isNil: - regs[ra] = copyTree(c.constants.sons[rb]) + let cnst = c.constants.sons[rb] + if fitsRegister(cnst.typ): + putIntoReg(regs[ra], cnst) else: - asgnComplex(regs[ra], c.constants.sons[rb]) + ensureKind(rkNode) + regs[ra].node = cnst.copyTree of opcLdGlobal: let rb = instr.regBx - wordExcess - 1 - if regs[ra].isNil: - regs[ra] = copyTree(c.globals.sons[rb]) - else: - asgnComplex(regs[ra], c.globals.sons[rb]) + ensureKind(rkNode) + regs[ra].node = c.globals.sons[rb] of opcRepr: - decodeB(nkStrLit) - regs[ra].strVal = renderTree(regs[rb].skipMeta, {renderNoComments}) + decodeB(rkNode) + createStr regs[ra] + regs[ra].node.strVal = renderTree(regs[rb].node, {renderNoComments}) of opcQuit: if c.mode in {emRepl, emStaticExpr, emStaticStmt}: message(c.debug[pc], hintQuitCalled) - quit(int(getOrdValue(regs[ra]))) + quit(int(getOrdValue(regs[ra].regToNode))) else: - return nil + return TRegister(kind: rkNone) of opcSetLenStr: - decodeB(nkStrLit) - regs[ra].strVal.setLen(regs[rb].getOrdValue.int) + decodeB(rkNode) + createStrKeepNode regs[ra] + regs[ra].node.strVal.setLen(regs[rb].intVal.int) of opcOf: - decodeBC(nkIntLit) + decodeBC(rkInt) let typ = c.types[regs[rc].intVal.int] - regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, typ) >= 0) + regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0) of opcIs: - decodeBC(nkIntLit) - let t1 = regs[rb].typ.skipTypes({tyTypeDesc}) + decodeBC(rkInt) + let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc}) let t2 = c.types[regs[rc].intVal.int] # XXX: This should use the standard isOpImpl let match = if t2.kind == tyUserTypeClass: true else: sameType(t1, t2) regs[ra].intVal = ord(match) of opcSetLenSeq: - decodeB(nkBracket) - let newLen = regs[rb].getOrdValue.int - setLen(regs[ra].sons, newLen) + decodeB(rkNode) + let newLen = regs[rb].intVal.int + if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess) + else: setLen(regs[ra].node.sons, newLen) of opcSwap, opcReset: internalError(c.debug[pc], "too implement") of opcIsNil: - decodeB(nkIntLit) - regs[ra].intVal = ord(regs[rb].skipMeta.kind == nkNilLit) + decodeB(rkInt) + regs[ra].intVal = ord(regs[rb].node.kind == nkNilLit) of opcNBindSym: - decodeBx(nkMetaNode) - setMeta(regs[ra], copyTree(c.constants.sons[rbx])) + decodeBx(rkNode) + regs[ra].node = copyTree(c.constants.sons[rbx]) of opcNChild: - decodeBC(nkMetaNode) - if regs[rb].kind != nkMetaNode: - internalError(c.debug[pc], "no MetaNode") + decodeBC(rkNode) let idx = regs[rc].intVal.int - let src = regs[rb].uast + let src = regs[rb].node if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len: - setMeta(regs[ra], src.sons[idx]) + regs[ra].node = src.sons[idx] else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcNSetChild: - decodeBC(nkMetaNode) + decodeBC(rkNode) let idx = regs[rb].intVal.int - var dest = regs[ra].uast + var dest = regs[ra].node if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len: - dest.sons[idx] = regs[rc].uast + dest.sons[idx] = regs[rc].node else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcNAdd: - decodeBC(nkMetaNode) - var u = regs[rb].uast - u.add(regs[rc].uast) - setMeta(regs[ra], u) + decodeBC(rkNode) + var u = regs[rb].node + u.add(regs[rc].node) + regs[ra].node = u of opcNAddMultiple: - decodeBC(nkMetaNode) - let x = regs[rc] - var u = regs[rb].uast + decodeBC(rkNode) + let x = regs[rc].node + var u = regs[rb].node # XXX can be optimized: - for i in 0.. <x.len: u.add(x.sons[i].skipMeta) - setMeta(regs[ra], u) + for i in 0.. <x.len: u.add(x.sons[i]) + regs[ra].node = u of opcNKind: - decodeB(nkIntLit) - regs[ra].intVal = ord(regs[rb].uast.kind) + decodeB(rkInt) + regs[ra].intVal = ord(regs[rb].node.kind) of opcNIntVal: - decodeB(nkIntLit) - let a = regs[rb].uast + decodeB(rkInt) + let a = regs[rb].node case a.kind of nkCharLit..nkInt64Lit: regs[ra].intVal = a.intVal else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal") of opcNFloatVal: - decodeB(nkFloatLit) - let a = regs[rb].uast + decodeB(rkFloat) + let a = regs[rb].node case a.kind of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal") of opcNSymbol: - decodeB(nkSym) - let a = regs[rb].uast + decodeB(rkNode) + let a = regs[rb].node if a.kind == nkSym: - regs[ra].sym = a.sym + regs[ra].node = copyNode(a) else: stackTrace(c, tos, pc, errFieldXNotFound, "symbol") of opcNIdent: - decodeB(nkIdent) - let a = regs[rb].uast + decodeB(rkNode) + let a = regs[rb].node if a.kind == nkIdent: - regs[ra].ident = a.ident + regs[ra].node = copyNode(a) else: stackTrace(c, tos, pc, errFieldXNotFound, "ident") of opcNGetType: internalError(c.debug[pc], "unknown opcode " & $instr.opcode) of opcNStrVal: - decodeB(nkStrLit) - let a = regs[rb].uast - case a.kind - of nkStrLit..nkTripleStrLit: regs[ra].strVal = a.strVal + decodeB(rkNode) + createStr regs[ra] + let a = regs[rb].node + if a.kind in {nkStrLit..nkTripleStrLit}: regs[ra].node.strVal = a.strVal else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal") of opcSlurp: - decodeB(nkStrLit) - regs[ra].strVal = opSlurp(regs[rb].strVal, c.debug[pc], c.module) + decodeB(rkNode) + createStr regs[ra] + regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc], + c.module) of opcGorge: - decodeBC(nkStrLit) - regs[ra].strVal = opGorge(regs[rb].strVal, regs[rc].strVal) + decodeBC(rkNode) + regs[ra].node.strVal = opGorge(regs[rb].node.strVal, + regs[rc].node.strVal) of opcNError: - stackTrace(c, tos, pc, errUser, regs[ra].strVal) + stackTrace(c, tos, pc, errUser, regs[ra].node.strVal) of opcNWarning: - message(c.debug[pc], warnUser, regs[ra].strVal) + message(c.debug[pc], warnUser, regs[ra].node.strVal) of opcNHint: - message(c.debug[pc], hintUser, regs[ra].strVal) + message(c.debug[pc], hintUser, regs[ra].node.strVal) of opcParseExprToAst: - decodeB(nkMetaNode) + decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? - let ast = parseString(regs[rb].strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, c.debug[pc].line.int) if sonsLen(ast) != 1: globalError(c.debug[pc], errExprExpected, "multiple statements") - setMeta(regs[ra], ast.sons[0]) + regs[ra].node = ast.sons[0] of opcParseStmtToAst: - decodeB(nkMetaNode) - let ast = parseString(regs[rb].strVal, c.debug[pc].toFilename, + decodeB(rkNode) + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, c.debug[pc].line.int) - setMeta(regs[ra], ast) + regs[ra].node = ast of opcCallSite: - ensureKind(nkMetaNode) - if c.callsite != nil: setMeta(regs[ra], c.callsite) + ensureKind(rkNode) + if c.callsite != nil: regs[ra].node = c.callsite else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite") of opcNLineInfo: - decodeB(nkStrLit) - let n = regs[rb] - regs[ra].strVal = n.info.toFileLineCol - regs[ra].info = c.debug[pc] + decodeB(rkNode) + let n = regs[rb].node + createStr regs[ra] + regs[ra].node.strVal = n.info.toFileLineCol + regs[ra].node.info = c.debug[pc] of opcEqIdent: - decodeBC(nkIntLit) - if regs[rb].kind == nkIdent and regs[rc].kind == nkIdent: - regs[ra].intVal = ord(regs[rb].ident.id == regs[rc].ident.id) + decodeBC(rkInt) + if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent: + regs[ra].intVal = ord(regs[rb].node.ident.id == regs[rc].node.ident.id) else: regs[ra].intVal = 0 of opcStrToIdent: - decodeB(nkIdent) - if regs[rb].kind notin {nkStrLit..nkTripleStrLit}: + decodeB(rkNode) + if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}: stackTrace(c, tos, pc, errFieldXNotFound, "strVal") else: - regs[ra].info = c.debug[pc] - regs[ra].ident = getIdent(regs[rb].strVal) + regs[ra].node = newNodeI(nkIdent, c.debug[pc]) + regs[ra].node.ident = getIdent(regs[rb].node.strVal) of opcIdentToStr: - decodeB(nkStrLit) - let a = regs[rb] - regs[ra].info = c.debug[pc] + decodeB(rkNode) + let a = regs[rb].node + createStr regs[ra] + regs[ra].node.info = c.debug[pc] if a.kind == nkSym: - regs[ra].strVal = a.sym.name.s + regs[ra].node.strVal = a.sym.name.s elif a.kind == nkIdent: - regs[ra].strVal = a.ident.s + regs[ra].node.strVal = a.ident.s else: stackTrace(c, tos, pc, errFieldXNotFound, "ident") of opcSetType: - regs[ra].typ = c.types[instr.regBx - wordExcess] + if regs[ra].kind != rkNode: + internalError(c.debug[pc], "cannot set type") + regs[ra].node.typ = c.types[instr.regBx - wordExcess] of opcConv: let rb = instr.regB inc pc - let typ = c.types[c.code[pc].regBx - wordExcess] - if opConv(regs[ra], regs[rb], typ): + let desttyp = c.types[c.code[pc].regBx - wordExcess] + inc pc + let srctyp = c.types[c.code[pc].regBx - wordExcess] + + if opConv(regs[ra], regs[rb], desttyp, srctyp): stackTrace(c, tos, pc, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [ - "unknown type" , "unknown type"]) + typeToString(srctyp), typeToString(desttyp)]) of opcCast: let rb = instr.regB inc pc - let typ = c.types[c.code[pc].regBx - wordExcess] + let desttyp = c.types[c.code[pc].regBx - wordExcess] + inc pc + let srctyp = c.types[c.code[pc].regBx - wordExcess] + when hasFFI: - let dest = fficast(regs[rb], typ) + let dest = fficast(regs[rb], desttyp) asgnRef(regs[ra], dest) else: globalError(c.debug[pc], "cannot evaluate cast") of opcNSetIntVal: - decodeB(nkMetaNode) - var dest = regs[ra].uast + decodeB(rkNode) + var dest = regs[ra].node if dest.kind in {nkCharLit..nkInt64Lit} and - regs[rb].kind in {nkCharLit..nkInt64Lit}: + regs[rb].kind in {rkInt}: dest.intVal = regs[rb].intVal else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal") of opcNSetFloatVal: - decodeB(nkMetaNode) - var dest = regs[ra].uast + decodeB(rkNode) + var dest = regs[ra].node if dest.kind in {nkFloatLit..nkFloat64Lit} and - regs[rb].kind in {nkFloatLit..nkFloat64Lit}: + regs[rb].kind in {rkFloat}: dest.floatVal = regs[rb].floatVal else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal") of opcNSetSymbol: - decodeB(nkMetaNode) - var dest = regs[ra].uast - if dest.kind == nkSym and regs[rb].kind == nkSym: - dest.sym = regs[rb].sym + decodeB(rkNode) + var dest = regs[ra].node + if dest.kind == nkSym and regs[rb].node.kind == nkSym: + dest.sym = regs[rb].node.sym else: stackTrace(c, tos, pc, errFieldXNotFound, "symbol") of opcNSetIdent: - decodeB(nkMetaNode) - var dest = regs[ra].uast - if dest.kind == nkIdent and regs[rb].kind == nkIdent: - dest.ident = regs[rb].ident + decodeB(rkNode) + var dest = regs[ra].node + if dest.kind == nkIdent and regs[rb].node.kind == nkIdent: + dest.ident = regs[rb].node.ident else: stackTrace(c, tos, pc, errFieldXNotFound, "ident") of opcNSetType: - decodeB(nkMetaNode) - let b = regs[rb].skipMeta + decodeB(rkNode) + let b = regs[rb].node internalAssert b.kind == nkSym and b.sym.kind == skType - regs[ra].uast.typ = b.sym.typ + internalAssert regs[ra].node != nil + regs[ra].node.typ = b.sym.typ of opcNSetStrVal: - decodeB(nkMetaNode) - var dest = regs[ra].uast + decodeB(rkNode) + var dest = regs[ra].node if dest.kind in {nkStrLit..nkTripleStrLit} and - regs[rb].kind in {nkStrLit..nkTripleStrLit}: - dest.strVal = regs[rb].strVal + regs[rb].kind in {rkNode}: + dest.strVal = regs[rb].node.strVal else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal") of opcNNewNimNode: - decodeBC(nkMetaNode) + decodeBC(rkNode) var k = regs[rb].intVal - if k < 0 or k > ord(high(TNodeKind)) or k == ord(nkMetaNode): + if k < 0 or k > ord(high(TNodeKind)): internalError(c.debug[pc], "request to create a NimNode of invalid kind") - let cc = regs[rc].skipMeta - setMeta(regs[ra], newNodeI(TNodeKind(int(k)), - if cc.kind == nkNilLit: c.debug[pc] else: cc.info)) - regs[ra].sons[0].flags.incl nfIsRef + let cc = regs[rc].node + regs[ra].node = newNodeI(TNodeKind(int(k)), + if cc.kind == nkNilLit: c.debug[pc] else: cc.info) + regs[ra].node.flags.incl nfIsRef of opcNCopyNimNode: - decodeB(nkMetaNode) - setMeta(regs[ra], copyNode(regs[rb].skipMeta)) + decodeB(rkNode) + regs[ra].node = copyNode(regs[rb].node) of opcNCopyNimTree: - decodeB(nkMetaNode) - setMeta(regs[ra], copyTree(regs[rb])) + decodeB(rkNode) + regs[ra].node = copyTree(regs[rb].node) of opcNDel: - decodeBC(nkMetaNode) + decodeBC(rkNode) let bb = regs[rb].intVal.int for i in countup(0, regs[rc].intVal.int-1): - delSon(regs[ra].uast, bb) + delSon(regs[ra].node, bb) of opcGenSym: - decodeBC(nkMetaNode) + decodeBC(rkNode) let k = regs[rb].intVal - let name = if regs[rc].strVal.len == 0: ":tmp" else: regs[rc].strVal + let name = if regs[rc].node.strVal.len == 0: ":tmp" + else: regs[rc].node.strVal if k < 0 or k > ord(high(TSymKind)): internalError(c.debug[pc], "request to create symbol of invalid kind") var sym = newSym(k.TSymKind, name.getIdent, c.module, c.debug[pc]) incl(sym.flags, sfGenSym) - setMeta(regs[ra], newSymNode(sym)) + regs[ra].node = newSymNode(sym) of opcTypeTrait: # XXX only supports 'name' for now; we can use regC to encode the # type trait operation - decodeB(nkStrLit) - var typ = regs[rb].typ + decodeB(rkNode) + var typ = regs[rb].node.typ internalAssert typ != nil while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0] - regs[ra].strVal = typ.typeToString(preferExported) - of opcGlobalOnce: - let rb = instr.regBx - if c.globals.sons[rb - wordExcess - 1].kind != nkEmpty: - # skip initialization instructions: - while true: - inc pc - if c.code[pc].opcode in {opcWrGlobal, opcWrGlobalRef} and - c.code[pc].regBx == rb: - break - of opcGlobalAlias: - let rb = instr.regBx - wordExcess - 1 - regs[ra] = c.globals.sons[rb] + createStr regs[ra] + regs[ra].node.strVal = typ.typeToString(preferExported) inc pc proc fixType(result, n: PNode) {.inline.} = @@ -1074,8 +1148,7 @@ proc fixType(result, n: PNode) {.inline.} = proc execute(c: PCtx, start: int): PNode = var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil) newSeq(tos.slots, c.prc.maxSlots) - for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) - result = rawExecute(c, start, tos) + result = rawExecute(c, start, tos).regToNode proc evalStmt*(c: PCtx, n: PNode) = let n = transformExpr(c.module, n) @@ -1091,7 +1164,6 @@ proc evalExpr*(c: PCtx, n: PNode): PNode = assert c.code[start].opcode != opcEof result = execute(c, start) if not result.isNil: - result = result.skipMeta fixType(result, n) # for now we share the 'globals' environment. XXX Coming soon: An API for @@ -1138,8 +1210,8 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode = assert c.code[start].opcode != opcEof var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil) newSeq(tos.slots, c.prc.maxSlots) - for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) - result = rawExecute(c, start, tos) + #for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) + result = rawExecute(c, start, tos).regToNode fixType(result, n) proc evalConstExpr*(module: PSym, e: PNode): PNode = @@ -1151,13 +1223,13 @@ proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode = proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) = discard evalConstExprAux(module, prc, e, emStaticStmt) +proc setupCompileTimeVar*(module: PSym, n: PNode) = + discard evalConstExprAux(module, nil, n, emStaticStmt) + proc setupMacroParam(x: PNode): PNode = result = x if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1] - let y = result - y.flags.incl nfIsRef - result = newNode(nkMetaNode) - result.add y + result.flags.incl nfIsRef result.typ = x.typ var evalMacroCounter: int @@ -1183,15 +1255,16 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = # doesn't end up in the parameter: #InternalAssert tos.slots.len >= L # return value: - tos.slots[0] = newNodeIT(nkEmpty, n.info, sym.typ.sons[0]) + tos.slots[0].kind = rkNode + tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0]) # setup parameters: for i in 1 .. < min(tos.slots.len, L): - tos.slots[i] = setupMacroParam(n.sons[i]) + tos.slots[i].kind = rkNode + tos.slots[i].node = setupMacroParam(n.sons[i]) # temporary storage: - for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty) - result = rawExecute(c, start, tos) + #for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty) + result = rawExecute(c, start, tos).regToNode if cyclicTree(result): globalError(n.info, errCyclicTree) dec(evalMacroCounter) - if result != nil: - result = result.skipMeta c.callsite = nil + #debug result diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 87159c813..72689c879 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -8,7 +8,7 @@ # ## This module contains the type definitions for the new evaluation engine. -## An instruction is 1-2 int32s in memory, it is a register based VM. +## An instruction is 1-3 int32s in memory, it is a register based VM. import ast, passes, msgs, intsets @@ -32,17 +32,17 @@ type opcAsgnFloat, opcAsgnRef, opcAsgnComplex, + opcRegToNode, + opcNodeToReg, opcLdArr, # a = b[c] - opcLdArrRef, opcWrArr, # a[b] = c - opcWrArrRef, opcLdObj, # a = b.c - opcLdObjRef, opcWrObj, # a.b = c - opcWrObjRef, - opcAddr, - opcDeref, + opcAddrReg, + opcAddrNode, + opcLdDeref, + opcWrDeref, opcWrStrIdx, opcLdStrIdx, # a = b[c] @@ -117,15 +117,13 @@ type opcNew, opcNewSeq, opcLdNull, # dest = nullvalue(types[Bx]) + opcLdNullReg, opcLdConst, # dest = constants[Bx] opcAsgnConst, # dest = copy(constants[Bx]) opcLdGlobal, # dest = globals[Bx] + opcLdImmInt, # dest = immediate value opcNBindSym, - opcWrGlobal, - opcWrGlobalRef, - opcGlobalAlias, # load an alias to a global into a register - opcGlobalOnce, # used to introduce an assignment to a global once opcSetType, # dest.typ = types[Bx] opcTypeTrait @@ -165,8 +163,6 @@ type blocks*: seq[TBlock] # blocks; temp data structure slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] maxSlots*: int - globals*: array[TRegister, int] # hack: to support passing globals byref - # we map a slot persistently to a global PCtx* = ref TCtx TCtx* = object of passes.TPassContext # code gen context @@ -183,6 +179,7 @@ type callsite*: PNode mode*: TEvalMode features*: TSandboxFlags + traceActive*: bool TPosition* = distinct int diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 206cca0d7..b594c00a9 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -139,25 +139,12 @@ proc getTemp(c: PCtx; typ: PType): TRegister = if not c.slots[i].inUse: c.slots[i] = (inUse: true, kind: k) return TRegister(i) + if c.maxSlots >= high(TRegister): + internalError("cannot generate code; too many registers required") result = TRegister(c.maxSlots) c.slots[c.maxSlots] = (inUse: true, kind: k) inc c.maxSlots -proc getGlobalSlot(c: PCtx; n: PNode; s: PSym): TRegister = - let p = c.prc - for i in 0 .. p.maxSlots-1: - if p.globals[i] == s.id: return TRegister(i) - - result = TRegister(p.maxSlots) - p.slots[p.maxSlots] = (inUse: true, kind: slotFixedVar) - p.globals[p.maxSlots] = s.id - inc p.maxSlots - # XXX this is still not correct! We need to load the global in a proc init - # section, otherwise control flow could lead to a usage before it's been - # loaded. - c.gABx(n, opcGlobalAlias, result, s.position) - # XXX add some internal asserts here - proc freeTemp(c: PCtx; r: TRegister) = let c = c.prc if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false @@ -322,13 +309,7 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) = c.patch(L1) proc nilLiteral(n: PNode): PNode = - if n.kind == nkNilLit and n.typ.sym != nil and - n.typ.sym.magic == mPNimrodNode: - let nilo = newNodeIT(nkNilLit, n.info, n.typ) - result = newNodeIT(nkMetaNode, n.info, n.typ) - result.add nilo - else: - result = n + result = n proc rawGenLiteral(c: PCtx; n: PNode): int = result = c.constants.len @@ -470,21 +451,37 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = c.gABC(n, opcIndCallAsgn, dest, x, n.len) c.freeTempRange(x, n.len) +template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar + proc needsAsgnPatch(n: PNode): bool = - n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr} + n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, + nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal) proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = case le.kind of nkBracketExpr: - let dest = c.genx(le.sons[0]) + let dest = c.genx(le.sons[0], {gfAddrOf}) let idx = c.genx(le.sons[1]) - c.gABC(le, opcWrArrRef, dest, idx, value) + c.gABC(le, opcWrArr, dest, idx, value) + c.freeTemp(dest) + c.freeTemp(idx) of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] - let dest = c.genx(left.sons[0]) + let dest = c.genx(left.sons[0], {gfAddrOf}) let idx = c.genx(left.sons[1]) - c.gABC(left, opcWrObjRef, dest, idx, value) + c.gABC(left, opcWrObj, dest, idx, value) + c.freeTemp(dest) + c.freeTemp(idx) + of nkDerefExpr, nkHiddenDeref: + let dest = c.genx(le.sons[0], {gfAddrOf}) + c.gABC(le, opcWrDeref, dest, value) + c.freeTemp(dest) + of nkSym: + if le.sym.isGlobal: + let dest = c.genx(le, {gfAddrOf}) + c.gABC(le, opcWrDeref, dest, value) + c.freeTemp(dest) else: discard @@ -594,10 +591,10 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = let tmp = c.genx(arg) - c.gABx(n, opcSetType, tmp, genType(c, arg.typ)) if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opc, dest, tmp) c.gABx(n, opc, 0, genType(c, n.typ)) + c.gABx(n, opc, 0, genType(c, arg.typ)) c.freeTemp(tmp) proc genCard(c: PCtx; n: PNode; dest: var TDest) = @@ -623,6 +620,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = c.genAddSubInt(n, dest, opcAddInt) of mInc, mDec: unused(n, dest) + # XXX generates inefficient code for globals var d = c.genx(n.sons[1]).TDest c.genAddSubInt(n, d, if m == mInc: opcAddInt else: opcSubInt) c.genAsgnPatch(n.sons[1], d) @@ -636,6 +634,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = c.genNewSeq(n) of mNewString: genUnaryABC(c, n, dest, opcNewStr) + # XXX buggy of mNewStringOfCap: # we ignore the 'cap' argument and translate it as 'newString(0)'. # eval n.sons[1] for possible side effects: @@ -644,6 +643,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opcNewStr, dest, tmp) c.freeTemp(tmp) + # XXX buggy of mLengthOpenArray, mLengthArray, mLengthSeq: genUnaryABI(c, n, dest, opcLenSeq) of mLengthStr: @@ -905,6 +905,10 @@ const tyFloat, tyFloat32, tyFloat64, tyFloat128, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64} +proc fitsRegister*(t: PType): bool = + t.skipTypes(abstractInst-{tyTypeDesc}).kind in { + tyRange, tyEnum, tyBool, tyInt..tyUInt64} + proc requiresCopy(n: PNode): bool = if n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind in atomicTypes: result = false @@ -919,7 +923,8 @@ proc unneededIndirection(n: PNode): bool = proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; flags: TGenFlags) = # a nop for certain types - let flags = if opc == opcAddr: flags+{gfAddrOf} else: flags + let isAddr = opc in {opcAddrNode, opcAddrReg} + let flags = if isAddr: flags+{gfAddrOf} else: flags # consider: # proc foo(f: var ref int) = # f = new(int) @@ -929,12 +934,17 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; # # The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for # nkAddr we must not use 'unneededIndirection', but for deref we use it. - if opc != opcAddr and unneededIndirection(n.sons[0]): + if not isAddr and unneededIndirection(n.sons[0]): gen(c, n.sons[0], dest, flags) else: let tmp = c.genx(n.sons[0], flags) if dest < 0: dest = c.getTemp(n.typ) - gABC(c, n, opc, dest, tmp) + if not isAddr: + gABC(c, n, opc, dest, tmp) + elif c.prc.slots[tmp].kind >= slotTempUnknown: + gABC(c, n, opcAddrReg, dest, tmp) + else: + gABC(c, n, opcAddrNode, dest, tmp) c.freeTemp(tmp) proc whichAsgnOpc(n: PNode): TOpcode = @@ -952,8 +962,7 @@ proc whichAsgnOpc(n: PNode): TOpcode = proc isRef(t: PType): bool = t.skipTypes(abstractRange-{tyTypeDesc}).kind == tyRef -proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = - if isRef(n.typ): succ(opc) else: opc +proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) = let tmp = c.genx(ri) @@ -961,8 +970,6 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) = gABC(c, ri, whichAsgnOpc(ri), dest, tmp) c.freeTemp(tmp) -template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar - proc setSlot(c: PCtx; v: PSym) = # XXX generate type initialization here? if v.position == 0: @@ -974,29 +981,36 @@ proc setSlot(c: PCtx; v: PSym) = proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = case le.kind of nkBracketExpr: - let dest = c.genx(le.sons[0]) + let dest = c.genx(le.sons[0], {gfAddrOf}) let idx = c.genx(le.sons[1]) let tmp = c.genx(ri) if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in { tyString, tyCString}: c.gABC(le, opcWrStrIdx, dest, idx, tmp) else: - c.gABC(le, whichAsgnOpc(le, opcWrArr), dest, idx, tmp) + c.gABC(le, opcWrArr, dest, idx, tmp) c.freeTemp(tmp) of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] - let dest = c.genx(left.sons[0]) + let dest = c.genx(left.sons[0], {gfAddrOf}) let idx = c.genx(left.sons[1]) let tmp = c.genx(ri) - c.gABC(left, whichAsgnOpc(left, opcWrObj), dest, idx, tmp) + c.gABC(left, opcWrObj, dest, idx, tmp) + c.freeTemp(tmp) + of nkDerefExpr, nkHiddenDeref: + let dest = c.genx(le, {gfAddrOf}) + let tmp = c.genx(ri) + c.gABC(le, opcWrDeref, dest, tmp) c.freeTemp(tmp) of nkSym: let s = le.sym if s.isGlobal: withTemp(tmp, le.typ): - gen(c, ri, tmp) - c.gABx(le, whichAsgnOpc(le, opcWrGlobal), tmp, s.position) + c.gen(le, tmp, {gfAddrOf}) + let val = c.genx(ri) + c.gABC(le, opcWrDeref, tmp, val) + c.freeTemp(val) else: if s.kind == skForVar and c.mode == emRepl: c.setSlot s internalAssert s.position > 0 or (s.position == 0 and @@ -1004,7 +1018,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = var dest: TRegister = s.position + ord(s.kind == skParam) gen(c, ri, dest) else: - let dest = c.genx(le) + let dest = c.genx(le, {gfAddrOf}) genAsgn(c, dest, ri, requiresCopy) proc genLit(c: PCtx; n: PNode; dest: var TDest) = @@ -1034,18 +1048,22 @@ proc cannotEval(n: PNode) {.noinline.} = globalError(n.info, errGenerated, "cannot evaluate at compile time: " & n.renderTree) +proc getNullValue*(typ: PType, info: TLineInfo): PNode + proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = - c.globals.add(emptyNode.copyNode) + c.globals.add(getNullValue(s.typ, n.info)) s.position = c.globals.len # This is rather hard to support, due to the laziness of the VM code # generator. See tests/compile/tmacro2 for why this is necesary: # var decls{.compileTime.}: seq[PNimrodNode] = @[] - c.gABx(n, opcGlobalOnce, 0, s.position) + let dest = c.getTemp(s.typ) + c.gABx(n, opcLdGlobal, dest, s.position) let tmp = c.genx(s.ast) - c.gABx(n, whichAsgnOpc(n, opcWrGlobal), tmp, s.position) + c.gABC(n, opcWrDeref, dest, tmp) + c.freeTemp(dest) c.freeTemp(tmp) -proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = +proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let s = n.sym if s.isGlobal: if sfCompileTime in s.flags or c.mode == emRepl: @@ -1055,9 +1073,12 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = if s.position == 0: if sfImportc in s.flags: c.importcSym(n.info, s) else: genGlobalInit(c, n, s) - if dest < 0: - dest = c.getGlobalSlot(n, s) - #c.gABx(n, opcAliasGlobal, dest, s.position) + if dest < 0: dest = c.getTemp(n.typ) + if gfAddrOf notin flags and fitsRegister(s.typ): + var cc = c.getTemp(n.typ) + c.gABx(n, opcLdGlobal, cc, s.position) + c.gABC(n, opcNodeToReg, dest, cc) + c.freeTemp(cc) else: c.gABx(n, opcLdGlobal, dest, s.position) else: @@ -1078,7 +1099,13 @@ proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; let a = c.genx(n.sons[0], flags) let b = c.genx(n.sons[1], {}) if dest < 0: dest = c.getTemp(n.typ) - c.gABC(n, (if gfAddrOf in flags: succ(opc) else: opc), dest, a, b) + if gfAddrOf notin flags and fitsRegister(n.typ): + var cc = c.getTemp(n.typ) + c.gABC(n, opc, cc, a, b) + c.gABC(n, opcNodeToReg, dest, cc) + c.freeTemp(cc) + else: + c.gABC(n, opc, dest, a, b) c.freeTemp(a) c.freeTemp(b) @@ -1096,7 +1123,6 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = else: genAccess(c, n, dest, opcLdArr, flags) -proc getNullValue*(typ: PType, info: TLineInfo): PNode proc getNullValueAux(obj: PNode, result: PNode) = case obj.kind of nkRecList: @@ -1121,12 +1147,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkFloatLit, info, t) of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr, tyStmt, tyTypeDesc, tyStatic, tyRef: - if t.sym != nil and t.sym.magic == mPNimrodNode: - let nilo = newNodeIT(nkNilLit, info, t) - result = newNodeIT(nkMetaNode, info, t) - result.add nilo - else: - result = newNodeIT(nkNilLit, info, t) + result = newNodeIT(nkNilLit, info, t) of tyProc: if t.callConv != ccClosure: result = newNodeIT(nkNilLit, info, t) @@ -1154,6 +1175,9 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkCurly, info, t) else: internalError("getNullValue: " & $t.kind) +proc ldNullOpcode(t: PType): TOpcode = + if fitsRegister(t): opcLdNullReg else: opcLdNull + proc genVarSection(c: PCtx; n: PNode) = for a in n: if a.kind == nkCommentStmt: continue @@ -1164,8 +1188,8 @@ proc genVarSection(c: PCtx; n: PNode) = setSlot(c, a[i].sym) # v = t[i] var v: TDest = -1 - genRdVar(c, a[i], v) - c.gABC(n, opcLdObj, v, tmp, i) + genRdVar(c, a[i], v, {gfAddrOf}) + c.gABC(n, opcWrObj, v, tmp, i) # XXX globals? c.freeTemp(tmp) elif a.sons[0].kind == nkSym: @@ -1177,27 +1201,28 @@ proc genVarSection(c: PCtx; n: PNode) = let sa = if s.ast.isNil: getNullValue(s.typ, a.info) else: s.ast c.globals.add(sa) s.position = c.globals.len - # "Once support" is unnecessary here if a.sons[2].kind == nkEmpty: when false: withTemp(tmp, s.typ): c.gABx(a, opcLdNull, tmp, c.genType(s.typ)) c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position) else: - let tmp = genx(c, a.sons[2]) - c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position) + let tmp = c.genx(a.sons[0], {gfAddrOf}) + let val = c.genx(a.sons[2]) + c.gABC(a, opcWrDeref, tmp, val) + c.freeTemp(val) c.freeTemp(tmp) else: setSlot(c, s) if a.sons[2].kind == nkEmpty: - c.gABx(a, opcLdNull, s.position, c.genType(s.typ)) + c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ)) else: gen(c, a.sons[2], s.position.TRegister) else: # assign to a.sons[0]; happens for closures if a.sons[2].kind == nkEmpty: let tmp = genx(c, a.sons[0]) - c.gABx(a, opcLdNull, tmp, c.genType(a.sons[0].typ)) + c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a.sons[0].typ)) c.freeTemp(tmp) else: genAsgn(c, a.sons[0], a.sons[2], true) @@ -1205,10 +1230,19 @@ proc genVarSection(c: PCtx; n: PNode) = proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABx(n, opcLdNull, dest, c.genType(n.typ)) + + let intType = getSysType(tyInt) + let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc}) + if seqType.kind == tySequence: + var tmp = c.getTemp(intType) + c.gABx(n, opcLdImmInt, tmp, n.len) + c.gABx(n, opcNewSeq, dest, c.genType(seqType)) + c.gABx(n, opcNewSeq, tmp, 0) + c.freeTemp(tmp) + if n.len > 0: - let intType = getSysType(tyInt) var tmp = getTemp(c, intType) - c.gABx(n, opcLdNull, tmp, c.genType(intType)) + c.gABx(n, opcLdNullReg, tmp, c.genType(intType)) for x in n: let a = c.genx(x) c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a) @@ -1274,7 +1308,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = let s = n.sym case s.kind of skVar, skForVar, skTemp, skLet, skParam, skResult: - genRdVar(c, n, dest) + genRdVar(c, n, dest, flags) of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator: # 'skTemplate' is only allowed for 'getAst' support: if sfImportc in s.flags: c.importcSym(n.info, s) @@ -1320,8 +1354,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of nkDotExpr: genObjAccess(c, n, dest, flags) of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags) of nkBracketExpr: genArrAccess(c, n, dest, flags) - of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcDeref, flags) - of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddr, flags) + of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags) + of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags) of nkWhenStmt, nkIfStmt, nkIfExpr: genIf(c, n, dest) of nkCaseStmt: genCase(c, n, dest) of nkWhileStmt: @@ -1506,7 +1540,7 @@ proc genProc(c: PCtx; s: PSym): int = c.gABC(body, opcEof, eofInstr.regA) c.optimizeJumps(result) s.offset = c.prc.maxSlots - #if s.name.s == "concatStyleInterpolation": + #if s.name.s == "importImpl_forward" or s.name.s == "importImpl": # c.echoCode(result) # echo renderTree(body) c.prc = oldPrc diff --git a/tests/macros/tmacro5.nim b/tests/macros/tmacro5.nim index 39324e497..9882ad90d 100644 --- a/tests/macros/tmacro5.nim +++ b/tests/macros/tmacro5.nim @@ -51,7 +51,7 @@ macro okayy:stmt = for node in decls: result.add node for node in impls: result.add node -importimpl(Item, int): +importImpl(Item, int): echo 42 importImpl(Foo, int16): echo 77 diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index 8226b0b04..d9c933939 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -18,10 +18,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # -when defined(Linux): - const Lib = "libchipmunk.so.6.1.1" -else: - {.error: "Platform unsupported".} + +const Lib = "libchipmunk.so.6.1.1" + when defined(MoreNimrod): {.hint: "MoreNimrod defined; some Chipmunk functions replaced in Nimrod".} {.deadCodeElim: on.} diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index ad43c69b7..df1b743ee 100644 --- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -17,10 +17,9 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -when defined(Linux): - const Lib = "libenet.so.1(|.0.3)" -else: - {.error: "Your platform has not been accounted for."} + +const Lib = "libenet.so.1(|.0.3)" + {.deadCodeElim: ON.} const ENET_VERSION_MAJOR* = 1 @@ -267,7 +266,7 @@ const ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000 ENET_PEER_FREE_RELIABLE_WINDOWS = 8 -when defined(Linux): +when defined(Linux) or true: import posix const ENET_SOCKET_NULL*: cint = -1 diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim index 27163e271..0d09d40e3 100644 --- a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim @@ -6,7 +6,12 @@ when defined(linux): LibS = "libcsfml-system.so.2.0" LibW = "libcsfml-window.so.2.0" else: - {.error: "Platform unsupported".} + # We only compile for testing here, so it doesn't matter it's not supported + const + LibG = "libcsfml-graphics.so.2.0" + LibS = "libcsfml-system.so.2.0" + LibW = "libcsfml-window.so.2.0" + #{.error: "Platform unsupported".} {.deadCodeElim: on.} {.pragma: pf, pure, final.} type @@ -153,8 +158,9 @@ type KeyF15, #/< The F15 key KeyPause, #/< The Pause key KeyCount #/< Keep last -- the total number of keyboard keys -when defined(linux): #or defined(bsd) ?? - type TWindowHandle* = clong + +type TWindowHandle* = clong + #elif defined(mac): # type TWindowHandle* = pointer ##typedef void* sfWindowHandle; <- whatever the hell that is #elif defined(windows): diff --git a/todo.txt b/todo.txt index d3ed9957f..4bee45516 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,6 @@ version 0.9.4 ============= -- fix macros\tstringinterp.nim: - - problem: needs another level of indirection for 'seq' - - problem: deref is not correct - fix GC issues - test and fix showoff @@ -26,7 +23,6 @@ version 0.9.x - implement 'union' and 'bits' pragmas - fix closures -- test and fix exception handling - ensure (ref T)(a, b) works as a type conversion and type constructor - optimize 'genericReset'; 'newException' leads to code bloat - stack-less GC @@ -40,7 +36,7 @@ version 0.9.x - built-in 'getImpl' - change comment handling in the AST; that's lots of work as c2nim and pas2nim - make use of the fast every node can have a comment! + make use of the fact every node can have a comment! version 0.9.X |