mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-24 01:38:33 +00:00
simplifies code, remove globals and double layer macro, employ macrocache
This commit is contained in:
parent
fff049abe8
commit
99a5eefcce
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user