diff --git a/core/vm/aot.go b/core/vm/aot.go
new file mode 100644
index 0000000000..97b066230a
--- /dev/null
+++ b/core/vm/aot.go
@@ -0,0 +1,233 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Copyright (c) 2018 Timo Savola. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vm
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "log"
+ "os"
+ "reflect"
+ "syscall"
+ "unsafe"
+
+ "github.com/ethereum/go-ethereum/core/vm/aot"
+
+ "github.com/tsavola/wag"
+ "github.com/tsavola/wag/buffer"
+ "github.com/tsavola/wag/compile"
+ "github.com/tsavola/wag/object/debug/dump"
+ "github.com/tsavola/wag/wa"
+)
+
+const linearMemoryAddressSpace = 8 * 1024 * 1024 * 1024
+const signalStackReserve = 8192
+const goStackVectorOffset = -4 * 8
+
+type importFunc struct {
+ index int
+ params int
+}
+
+func makeMem(size int, prot, extraFlags int) (mem []byte, err error) {
+ if size > 0 {
+ mem, err = syscall.Mmap(-1, 0, size, prot, syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS|extraFlags)
+ }
+ return
+}
+
+func memAddr(mem []byte) uintptr {
+ return (*reflect.SliceHeader)(unsafe.Pointer(&mem)).Data
+}
+
+func alignSize(size, alignment int) int {
+ return (size + (alignment - 1)) &^ (alignment - 1)
+}
+
+func GrowMemory(size int32) {
+
+}
+
+// AoTContract
+type AoTContract struct {
+ Code []byte
+ Num int
+ ImportVector []byte
+ ImportFuncs map[string]importFunc
+}
+
+func NewAoTContract(code []byte, num int) *AoTContract {
+ ret := &AoTContract{Code: code, Num: num}
+ ret.ImportFuncs = make(map[string]importFunc)
+ ret.ImportVector = make([]byte, (5+4)*8)
+
+ binary.LittleEndian.PutUint64(ret.ImportVector[0:], aot.ImportUseGas())
+ binary.LittleEndian.PutUint64(ret.ImportVector[8:], aot.ImportCallDataCopy())
+ binary.LittleEndian.PutUint64(ret.ImportVector[16:], aot.ImportGetCallDataSize())
+ binary.LittleEndian.PutUint64(ret.ImportVector[24:], aot.ImportFinish())
+ binary.LittleEndian.PutUint64(ret.ImportVector[32:], aot.ImportRevert())
+ ret.ImportFuncs["useGas"] = importFunc{-9, 1}
+ ret.ImportFuncs["callDataCopy"] = importFunc{-8, 3}
+ ret.ImportFuncs["getCallDataSize"] = importFunc{-7, 0}
+ ret.ImportFuncs["finish"] = importFunc{-6, 2}
+ ret.ImportFuncs["revert"] = importFunc{-5, 2}
+
+ binary.LittleEndian.PutUint64(ret.ImportVector[56:], aot.ImportGrowMemoryHandler())
+
+ return ret
+}
+
+func (ac *AoTContract) ResolveFunc(module, field string, sig wa.FuncType) (index int, err error) {
+ if module != "ethereum" {
+ err = fmt.Errorf("import function's module is unknown: %s %s", module, field)
+ return
+ }
+
+ i := ac.ImportFuncs[field]
+ if i.index == 0 {
+ err = fmt.Errorf("import function not supported: %s", field)
+ return
+ }
+ if len(sig.Params) != i.params {
+ err = fmt.Errorf("%s: import function has wrong number of parameters: import signature has %d, syscall wrapper has %d", field, len(sig.Params), i.params)
+ return
+ }
+
+ index = i.index
+ return
+}
+
+func (ac *AoTContract) ResolveGlobal(module, field string, t wa.Type) (init uint64, err error) {
+ err = fmt.Errorf("imported global not supported: %s %s", module, field)
+ return
+}
+
+func (ac *AoTContract) RequiredGas(code []byte) uint64 {
+ return 0
+}
+
+func (ac *AoTContract) Run(input []byte, contract *Contract) ([]byte, error) {
+ var (
+ textSize = compile.DefaultMaxTextSize
+ stackSize = wa.PageSize
+ entry = "main"
+ dumpText = false
+ )
+
+ progReader := bytes.NewReader(input)
+
+ vecSize := alignSize(len(ac.ImportVector), os.Getpagesize())
+
+ vecTextMem, err := makeMem(vecSize+textSize, syscall.PROT_READ|syscall.PROT_WRITE, 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ vecMem := vecTextMem[:vecSize]
+ copy(vecMem[vecSize-len(ac.ImportVector):], ac.ImportVector)
+
+ contractData := make([]byte, 8+8+8+len(input) /* original rsp + gas + size + data */)
+ binary.LittleEndian.PutUint64(contractData[8:], contract.Gas)
+ binary.LittleEndian.PutUint64(contractData[16:], uint64(len(input)))
+ copy(contractData[24:], input)
+ cdAddr := uint64(memAddr(contractData))
+ binary.LittleEndian.PutUint64(vecTextMem[vecSize-4*8:], cdAddr)
+
+ textMem := vecTextMem[vecSize:]
+ textAddr := memAddr(textMem)
+ textBuf := buffer.NewStatic(textMem[:0], len(textMem))
+
+ config := &wag.Config{
+ Text: textBuf,
+ MemoryAlignment: os.Getpagesize(),
+ Entry: entry,
+ }
+ obj, err := wag.Compile(config, progReader, ac)
+ if dumpText && len(obj.Text) > 0 {
+ e := dump.Text(os.Stdout, obj.Text, textAddr, obj.FuncAddrs, &obj.Names)
+ if err == nil {
+ err = e
+ }
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ binary.LittleEndian.PutUint64(ac.ImportVector[40:], uint64(obj.InitialMemorySize))
+
+ globalsMemory, err := makeMem(obj.MemoryOffset+linearMemoryAddressSpace, syscall.PROT_NONE, 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = syscall.Mprotect(globalsMemory[:obj.MemoryOffset+obj.InitialMemorySize], syscall.PROT_READ|syscall.PROT_WRITE)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ copy(globalsMemory, obj.GlobalsMemory)
+
+ memoryAddr := memAddr(globalsMemory) + uintptr(obj.MemoryOffset)
+
+ if err := syscall.Mprotect(vecMem, syscall.PROT_READ); err != nil {
+ log.Fatal(err)
+ }
+
+ if err := syscall.Mprotect(textMem, syscall.PROT_READ|syscall.PROT_EXEC); err != nil {
+ log.Fatal(err)
+ }
+
+ stackMem, err := makeMem(stackSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_STACK)
+ if err != nil {
+ log.Fatal(err)
+ }
+ stackOffset := stackSize - len(obj.StackFrame)
+ copy(stackMem[stackOffset:], obj.StackFrame)
+
+ stackAddr := memAddr(stackMem)
+ stackLimit := stackAddr + signalStackReserve
+ stackPtr := stackAddr + uintptr(stackOffset)
+
+ if stackLimit >= stackPtr {
+ log.Fatal("stack is too small for starting program")
+ }
+
+ retaddr, retsize := aot.Exec(textAddr, stackLimit, memoryAddr, stackPtr)
+
+ gasLeft := binary.LittleEndian.Uint64(contractData[8:])
+ if gasLeft == 0xffffffffffffffff {
+ fmt.Println("Out of gas")
+ return nil, ErrOutOfGas
+ } else {
+ fmt.Println("gas left: ", gasLeft, "result: ", globalsMemory[retaddr+obj.MemoryOffset:retaddr+obj.MemoryOffset+retsize])
+ contract.Gas = gasLeft
+ if retsize == 0 {
+ return nil, nil
+ }
+
+ retData := make([]byte, retsize)
+ copy(retData, globalsMemory[retaddr+obj.MemoryOffset:retaddr+obj.MemoryOffset+retsize])
+ return retData, nil
+ }
+
+ // TODO cleanup all protected memory areas
+}
diff --git a/core/vm/aot/eei.go b/core/vm/aot/eei.go
new file mode 100644
index 0000000000..ab0f6e53fe
--- /dev/null
+++ b/core/vm/aot/eei.go
@@ -0,0 +1,24 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package aot
+
+func ImportGetCallDataSize() uint64
+func ImportUseGas() uint64
+func ImportCallDataCopy() uint64
+func ImportFinish() uint64
+func ImportRevert() uint64
+func ImportGrowMemoryHandler() uint64
diff --git a/core/vm/aot/eei_amd64.s b/core/vm/aot/eei_amd64.s
new file mode 100644
index 0000000000..722d3543d5
--- /dev/null
+++ b/core/vm/aot/eei_amd64.s
@@ -0,0 +1,153 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+#include "textflag.h"
+
+TEXT ·ImportGetCallDataSize(SB),$0-8
+ LEAQ ethereumGetCallDataSize<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ethereumGetCallDataSize<>(SB),NOSPLIT,$0
+ // Get pointer to the contract info area into r13
+ MOVQ -0x20(R15), R13
+ MOVQ 0x10(R13), AX
+ RET
+
+TEXT ·ImportUseGas(SB),$0-8
+ LEAQ ethereumUseGas<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ethereumUseGas<>(SB),NOSPLIT,$0
+ // Get pointer to the contract info area into r13
+ MOVQ -0x20(R15), R13
+
+ MOVQ 8(SP), AX // Gas required
+ MOVQ 0x8(R13), CX // Gas left
+ CMPQ AX, CX
+ JA oog
+
+ SUBQ AX, CX
+ MOVQ CX, 0x8(R13)
+ XORQ AX, AX
+ XORQ CX, CX
+ RET
+
+ oog:
+ // Set gas value to -1
+ XORQ AX, AX
+ NOTQ AX
+ MOVQ AX, 0x8(R13)
+ // Recover the saved value of the stack
+ MOVQ -0x20(R15), SI
+ MOVQ (SI), SP
+ RET
+
+TEXT ·ImportCallDataCopy(SB),$0-8
+ LEAQ ethereumCallDataCopy<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ethereumCallDataCopy<>(SB),NOSPLIT,$0
+ // Get pointer to the contract info area into r13
+ MOVQ -0x20(R15), R13
+
+ // Get pointer to input data
+ MOVQ R13, SI
+ ADDQ $0x18, SI // start of input buffer
+ MOVQ 0x10(SP), AX // rax = input data offset
+ ADDQ AX, SI
+
+ // Load and check the size of data to be
+ // copied to the destination buffer
+ MOVQ 0x8(SP), CX // rcx = number of bytes
+ ADDQ CX, AX // rax = input buffer + nbytes
+ MOVQ 0x10(R13), R12 // r12 = max size
+ CMPQ AX, R12
+ JA eei_error
+
+ // Load address of the destination buffer
+ MOVQ 0x18(SP), DI
+ ADDQ R14, DI
+
+ copy:
+ MOVB (SI), AX
+ MOVB AX, (DI)
+ ADDQ $1, SI
+ ADDQ $1, DI
+ LOOP copy
+ RET
+
+ eei_error:
+ // Recover the saved value of the stack
+ MOVQ -0x20(R15), SI
+ MOVQ (SI), SP
+ RET
+
+TEXT ·ImportFinish(SB),$0-8
+ LEAQ ethereumFinish<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+// Voir si je peux mettre $0-16 et ret+0(FP), ret+8(FP)
+TEXT ethereumFinish<>(SB),NOSPLIT,$0
+ // Get both arguments from the stack, before it
+ // is changed back to its previous value
+ MOVQ 8(SP), AX
+ MOVQ 16(SP), CX
+
+ // Recover the saved value of the stack
+ MOVQ -0x20(R15), SI
+ MOVQ (SI), SP
+
+ // Store the buffer addresses and size at
+ // the location where go expects both parameters
+ // to be stored, on the initial stack.
+ MOVQ CX, 0x28(SP)
+ MOVQ AX, 0x30(SP)
+ RET
+
+TEXT ·ImportRevert(SB),$0-8
+ LEAQ ethereumRevert<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ethereumRevert<>(SB),NOSPLIT,$0
+ // Get both arguments from the stack, before it
+ // is changed back to its previous value
+ MOVQ 8(SP), AX
+ MOVQ 16(SP), CX
+
+ // Recover the saved value of the stack
+ MOVQ -0x20(R15), SI
+ MOVQ (SI), SP
+
+ // Store the buffer addresses and size at
+ // the location where go expects both parameters
+ // to be stored, on the initial stack.
+ MOVQ CX, 0x28(SP)
+ MOVQ AX, 0x30(SP)
+ RET
+
+TEXT ·ImportGrowMemoryHandler(SB),$0-8
+ LEAQ growMemoryHandler<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT growMemoryHandler<>(SB),NOSPLIT,$0-8
+ //CALL main·GrowMemory+0(FP)
+ RET
diff --git a/core/vm/aot/exec.go b/core/vm/aot/exec.go
new file mode 100644
index 0000000000..4f92bb3270
--- /dev/null
+++ b/core/vm/aot/exec.go
@@ -0,0 +1,9 @@
+// Copyright (c) 2018 Timo Savola. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aot
+
+func Exec(textBase, stackLimit, memoryBase, stackPtr uintptr) (int, int)
+func ImportTrapHandler() uint64
+func ImportGrowMemory() uint64
diff --git a/core/vm/aot/exec_amd64.s b/core/vm/aot/exec_amd64.s
new file mode 100644
index 0000000000..d138d6e91e
--- /dev/null
+++ b/core/vm/aot/exec_amd64.s
@@ -0,0 +1,77 @@
+// Copyright (c) 2018 Timo Savola. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+#include "textflag.h"
+
+// func exec(textBase, stackLimit, memoryBase, stackPtr uintptr)
+TEXT ·Exec(SB),NOSPLIT,$0-48
+ MOVQ textBase+0(FP), R15
+ MOVQ stackLimit+8(FP), BX
+ MOVQ memoryBase+16(FP), R14
+ MOVQ stackPtr+24(FP), CX
+
+ MOVQ -0x20(R15), DI
+ MOVQ SP, (DI)
+
+ MOVQ CX, SP // stack ptr
+
+ XORL AX, AX
+ XORL CX, CX
+ XORL BP, BP
+ XORL SI, SI
+ XORL DI, DI
+ XORL R8, R8
+ XORL R9, R9
+ XORL R10, R10
+ XORL R11, R11
+ XORL R12, R12
+ XORL R13, R13
+
+ MOVQ R15, DX
+ ADDQ $32, DX // init routine
+ JMP DX
+
+// func importTrapHandler() uint64
+TEXT ·ImportTrapHandler(SB),$0-8
+ LEAQ trapHandler<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT trapHandler<>(SB),NOSPLIT,$0
+ CMPL AX, $0 // exit trap (lower 32 bits)
+ JE exittrap
+ ADDL $100, AX // 100 + trap id
+ JMP sysexit
+
+exittrap:
+ SHRQ $32, AX // exit code (higher 32 bits)
+sysexit:
+ MOVL AX, DI
+ MOVL $231, AX // exit_group syscall
+ SYSCALL
+
+// func importGrowMemory() uint64
+TEXT ·ImportGrowMemory(SB),$0-8
+ LEAQ growMemory<>(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT growMemory<>(SB),NOSPLIT,$0
+ HLT // TODO: implementation
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index f4cb4b2305..5affac0279 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -67,14 +67,14 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
// PrecompiledContractsEWASM contains the default set of pre-compiled Ethereum
// contracts used for Ethereum 1.x release.
var PrecompiledContractsEWASM = map[common.Address]PrecompiledContract{
- common.BytesToAddress([]byte{1}): newEWASMPrecompile(ewasmEcrecoverCode, 1),
- common.BytesToAddress([]byte{2}): newEWASMPrecompile(ewasmSha256HashCode, 2),
- common.BytesToAddress([]byte{3}): newEWASMPrecompile(ewasmRipemd160hashCode, 3),
- common.BytesToAddress([]byte{4}): newEWASMPrecompile(ewasmIdentityCode, 4),
- common.BytesToAddress([]byte{5}): newEWASMPrecompile(ewasmExpmodCode, 5),
- common.BytesToAddress([]byte{6}): newEWASMPrecompile(ewasmEcaddCode, 6),
- common.BytesToAddress([]byte{7}): newEWASMPrecompile(ewasmEcmulCode, 7),
- common.BytesToAddress([]byte{8}): newEWASMPrecompile(ewasmEcpairingCode, 8),
+ common.BytesToAddress([]byte{1}): NewAoTContract(ewasmEcrecoverCode, 1),
+ common.BytesToAddress([]byte{2}): NewAoTContract(ewasmSha256HashCode, 2),
+ common.BytesToAddress([]byte{3}): NewAoTContract(ewasmRipemd160hashCode, 3),
+ common.BytesToAddress([]byte{4}): NewAoTContract(ewasmIdentityCode, 4),
+ common.BytesToAddress([]byte{5}): NewAoTContract(ewasmExpmodCode, 5),
+ common.BytesToAddress([]byte{6}): NewAoTContract(ewasmEcaddCode, 6),
+ common.BytesToAddress([]byte{7}): NewAoTContract(ewasmEcmulCode, 7),
+ common.BytesToAddress([]byte{8}): NewAoTContract(ewasmEcpairingCode, 8),
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.