From 99a5eefcce99a0048c624482d5ca2ed76f719846 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 31 Jan 2019 13:35:07 +0700 Subject: [PATCH] simplifies code, remove globals and double layer macro, employ macrocache --- tests/macro_assembler.nim | 274 ++++++++++---------------------------- 1 file changed, 74 insertions(+), 200 deletions(-) diff --git a/tests/macro_assembler.nim b/tests/macro_assembler.nim index dc07fc7f0..5db392a23 100644 --- a/tests/macro_assembler.nim +++ b/tests/macro_assembler.nim @@ -1,6 +1,7 @@ import - macros, strutils, unittest, byteutils, chronicles, - ../nimbus/vm/interpreter/opcode_values, ranges, eth_common + macros, macrocache, strutils, unittest, + byteutils, chronicles, ranges, eth_common, + ../nimbus/vm/interpreter/opcode_values import options, json, os, eth_trie/[db, hexary], @@ -31,111 +32,16 @@ type data*: seq[byte] output*: seq[byte] - OpcodeDesc = object - numParams: int - -var - g_asm {.compileTime.}: Assembler - g_code {.compileTime.}: NimNode - g_lookup {.compileTime.}: array[256, OpcodeDesc] - -proc writeLUT(opcode: Op, numParams: int) {.compileTime.} = - g_lookup[ord(opcode)] = OpcodeDesc(numParams: numParams) - -proc initializeLUT() {.compileTime.} = - writeLUT(Stop, 0) - writeLUT(Add, 2) - writeLUT(Mul, 2) - writeLUT(Sub, 2) - writeLUT(Div, 2) - writeLUT(Sdiv, 2) - writeLUT(Mod, 2) - writeLUT(Smod, 2) - writeLUT(Addmod, 3) - writeLUT(Mulmod, 3) - writeLUT(Exp, 2) - writeLUT(SignExtend, 2) - - writeLUT(Lt, 2) - writeLUT(Gt, 2) - writeLUT(Slt, 2) - writeLUT(Sgt, 2) - writeLUT(Eq, 2) - writeLUT(IsZero, 1) - writeLUT(And, 2) - writeLUT(Or, 2) - writeLUT(Xor, 2) - writeLUT(Not, 1) - writeLUT(Byte, 2) - - writeLUT(Sha3, 2) - - writeLUT(Address, 0) - writeLUT(Balance, 1) - writeLUT(Origin, 0) - writeLUT(Caller, 0) - writeLUT(CallValue, 0) - writeLUT(CallDataLoad, 1) - writeLUT(CallDataSize, 0) - writeLUT(CallDataCopy, 3) - writeLUT(CodeSize, 0) - writeLUT(CodeCopy, 3) - writeLUT(GasPrice, 0) - writeLUT(ExtCodeSize, 1) - writeLUT(ExtCodeCopy, 4) - writeLUT(ReturnDataSize, 0) - writeLUT(ReturnDataCopy, 3) - - writeLUT(Blockhash, 1) - writeLUT(Coinbase, 0) - writeLUT(Timestamp, 0) - writeLUT(Number, 0) - writeLUT(Difficulty, 0) - writeLUT(GasLimit, 0) - - writeLUT(Pop, 1) - writeLUT(Mload, 1) - writeLUT(Mstore, 2) - writeLUT(Mstore8, 2) - writeLUT(Sload, 1) - writeLUT(Sstore, 2) - writeLUT(Jump, 1) - writeLUT(JumpI, 2) - writeLUT(Pc, 0) - writeLUT(Msize, 0) - writeLUT(Gas, 0) - writeLUT(JumpDest, 0) - - for i in Push1 .. Push32: - writeLUT(i, 1) - - for i in Dup1 .. Dup16: - writeLUT(i, 0) - - for i in Swap1 .. Swap16: - writeLUT(i, 0) - - for i in Log0 .. Log4: - writeLUT(i, 0) - - writeLUT(Create, 3) - writeLUT(Call, 7) - writeLUT(CallCode, 7) - writeLUT(Return, 2) - writeLUT(DelegateCall, 6) - writeLUT(StaticCall, 6) - writeLUT(Revert, 2) - writeLUT(Invalid, 1) - writeLUT(SelfDestruct, 1) +const + idToOpcode = CacheTable"NimbusMacroAssembler" static: - initializeLUT() + for n in Op: + idToOpcode[$n] = newLit(ord(n)) proc validateVMWord(val: string, n: NimNode): VMWord = - if val.len <= 2 or val.len > 66: - error("invalid hex string", n) - if not (val[0] == '0' and val[1] == 'x'): - error("invalid hex string", n) + if val.len <= 2 or val.len > 66: error("invalid hex string", n) + if not (val[0] == '0' and val[1] == 'x'): error("invalid hex string", n) let zerosLen = 64 - (val.len - 2) let value = repeat('0', zerosLen) & val.substr(2) hexToByteArray(value, result) @@ -176,44 +82,88 @@ proc parseData(list: NimNode): seq[byte] = n.expectKind(nnkStrLit) result.add hexToSeqByte(n.strVal) +proc parseLog(node: NimNode): Log = + node.expectKind(nnkPar) + for item in node: + item.expectKind(nnkExprColonExpr) + let label = item[0].strVal + let body = item[1] + case label.normalize + of "address": + body.expectKind(nnkStrLit) + let value = body.strVal + if value.len < 20: + error("bad address format", body) + hexToByteArray(value, result.address) + of "topics": + body.expectKind(nnkBracket) + for x in body: + result.topics.add validateVMWord(x.strVal, x) + of "data": + result.data = hexToSeqByte(body.strVal) + else:error("unknown log section '" & label & "'", item[0]) + +proc parseLogs(list: NimNode): seq[Log] = + result = @[] + list.expectKind nnkStmtList + for n in list: + result.add parseLog(n) + proc validateOpcode(sym: NimNode) = let typ = getTypeInst(sym) typ.expectKind(nnkSym) if $typ != "Op": error("unknown opcode '" & $sym & "'", sym) -proc addOpCode(opcode: Op, node: NimNode, params: varargs[string]) = - let lut = g_lookup[opcode.ord] - if lut.numParams > 0 and params.len > 0: - if lut.numParams != params.len: - error("Opcode '" & $opcode & "' expect " & $lut.numParams & " params, but got " & $params.len, node) +proc addOpCode(code: var seq[byte], node, params: NimNode) = + node.expectKind nnkSym + let opcode = Op(idToOpcode[node.strVal].intVal) case opcode of Push1..Push32: if params.len != 1: error("expect 1 param, but got " & $params.len, node) let paramWidth = (opcode.ord - 95) * 2 - var val = params[0] + params[0].expectKind nnkStrLit + var val = params[0].strVal if val[0] == '0' and val[1] == 'x': val = val.substr(2) if val.len != paramWidth: error("expected param with " & $paramWidth & " hex digits, got " & $val.len, node) - g_asm.code.add byte(opcode) - g_asm.code.add hexToSeqByte(val) + code.add byte(opcode) + code.add hexToSeqByte(val) else: error("invalid hex format", node) else: if params.len > 0: - for i in countDown(params.len - 1, 0): - g_asm.code.add byte(Push32) - g_asm.code.add validateVMWord(params[i], node) - g_asm.code.add byte(opcode) + error("there should be no param for this instruction", node) + code.add byte(opcode) -proc addLiteral(node: NimNode, rawCode: string) = - if rawCode[0] == '0' and rawCode[1] == 'x': - let val = rawCode.substr(2) - g_asm.code.add hexToSeqByte(val) - else: - error("invalid hex format", node) +proc parseCode(codes: NimNode): seq[byte] = + let emptyNode = newEmptyNode() + codes.expectKind nnkStmtList + var addStop = true + for pc, line in codes: + line.expectKind({nnkCommand, nnkIdent, nnkStrLit}) + if line.kind == nnkStrLit: + result.add hexToSeqByte(line.strVal) + elif line.kind == nnkIdent: + let sym = bindSym(line) + validateOpcode(sym) + result.addOpCode(sym, emptyNode) + if pc == codes.len - 1: + addStop = $sym != "Stop" + elif line.kind == nnkCommand: + let sym = bindSym(line[0]) + validateOpcode(sym) + var params = newNimNode(nnkBracket) + for i in 1 ..< line.len: + params.add line[i] + result.addOpCode(sym, params) + else: + error("unknown syntax: " & line.toStrLit.strVal, line) + + if addStop: + result.addOpCode(bindSym"Stop", emptyNode) proc generateVMProxy(boa: Assembler): NimNode = let vmProxy = genSym(nskProc, "vmProxy") @@ -309,54 +259,6 @@ proc generateVMProxy(boa: Assembler): NimNode = when defined(macro_assembler_debug): echo result.toStrLit.strVal -proc assemblerImpl(boa: var Assembler, codes: NimNode): NimNode = - g_code = codes - boa.code = @[] - codes.expectKind nnkStmtList - let macroName = genSym(nskMacro, "asmProxy") - var addStop = true - var body = newStmtList() - for pc, line in codes: - line.expectKind({nnkCommand, nnkIdent, nnkStrLit}) - if line.kind == nnkStrLit: - body.add quote do: - addLiteral(g_code[`pc`], `line`) - elif line.kind == nnkIdent: - let sym = bindSym(line) - validateOpcode(sym) - body.add quote do: - addOpCode(`sym`, g_code[`pc`]) - if pc == codes.len - 1: - if normalize($sym) == "stop": - addStop = false - elif line.kind == nnkCommand: - let ident = line[0] - let sym = bindSym(ident) - validateOpcode(sym) - var params = newNimNode(nnkBracket) - for i in 1 ..< line.len: - params.add line[i] - body.add quote do: - addOpCode(`sym`, g_code[`pc`], `params`) - else: - error("unknown syntax: " & line.toStrLit.strVal, line) - - let stop = ident("Stop") - if addStop: - body.add quote do: - addOpCode(`stop`, newEmptyNode()) - - let resIdent = ident("result") - - result = quote do: - macro `macroName`(): untyped = - `body` - `resIdent` = generateVMProxy(g_asm) - `macroName`() - - when defined(macro_assembler_debug): - echo result.toStrLit.strVal - const blockFile = "tests" / "fixtures" / "PersistBlockTests" / "block47205.json" @@ -500,36 +402,8 @@ proc runVM*(blockNumber: Uint256, chainDB: BaseChainDB, boa: Assembler): bool = result = true -proc parseLog(node: NimNode): Log = - node.expectKind(nnkPar) - for item in node: - item.expectKind(nnkExprColonExpr) - let label = item[0].strVal - let body = item[1] - case label.normalize - of "address": - body.expectKind(nnkStrLit) - let value = body.strVal - if value.len < 20: - error("bad address format", body) - hexToByteArray(value, result.address) - of "topics": - body.expectKind(nnkBracket) - for x in body: - result.topics.add validateVMWord(x.strVal, x) - of "data": - result.data = hexToSeqByte(body.strVal) - else:error("unknown log section '" & label & "'", item[0]) - -proc parseLogs(list: NimNode): seq[Log] = - result = @[] - list.expectKind nnkStmtList - for n in list: - result.add parseLog(n) - macro assembler*(list: untyped): untyped = - var boa: Assembler - boa.success = true + var boa = Assembler(success: true) list.expectKind nnkStmtList for callSection in list: callSection.expectKind(nnkCall) @@ -540,7 +414,7 @@ macro assembler*(list: untyped): untyped = let title = body[0] title.expectKind(nnkStrLit) boa.title = title.strVal - of "code" : result = assemblerImpl(boa, body) + of "code" : boa.code = parseCode(body) of "memory": boa.memory = parseVMWords(body) of "stack" : boa.stack = parseVMWords(body) of "storage": boa.storage = parseStorage(body) @@ -549,4 +423,4 @@ macro assembler*(list: untyped): untyped = of "data": boa.data = parseData(body) of "output": boa.output = parseData(body) else: error("unknown section '" & label & "'", callSection[0]) - g_asm = boa + result = boa.generateVMProxy()