Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
8c99a87a
Commit
8c99a87a
authored
Jan 27, 2015
by
obscuren
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'chfast-pr/evmjit' into develop
parents
48083608
fe14b0b8
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
370 additions
and
18 deletions
+370
-18
.gitignore
.gitignore
+2
-0
gh_test.go
tests/vm/gh_test.go
+9
-9
vm_jit.go
vm/vm_jit.go
+349
-9
vm_jit_fake.go
vm/vm_jit_fake.go
+10
-0
No files found.
.gitignore
View file @
8c99a87a
...
...
@@ -15,3 +15,5 @@
.#*
*#
*~
.project
.settings
tests/vm/gh_test.go
View file @
8c99a87a
...
...
@@ -172,47 +172,47 @@ func RunVmTest(p string, t *testing.T) {
// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func
TestVMArithmetic
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmArithmeticTest.json"
const
fn
=
"../files/
VMT
ests/vmArithmeticTest.json"
RunVmTest
(
fn
,
t
)
}
func
TestBitwiseLogicOperation
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmBitwiseLogicOperationTest.json"
const
fn
=
"../files/
VMT
ests/vmBitwiseLogicOperationTest.json"
RunVmTest
(
fn
,
t
)
}
func
TestBlockInfo
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmBlockInfoTest.json"
const
fn
=
"../files/
VMT
ests/vmBlockInfoTest.json"
RunVmTest
(
fn
,
t
)
}
func
TestEnvironmentalInfo
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmEnvironmentalInfoTest.json"
const
fn
=
"../files/
VMT
ests/vmEnvironmentalInfoTest.json"
RunVmTest
(
fn
,
t
)
}
func
TestFlowOperation
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmIOandFlowOperationsTest.json"
const
fn
=
"../files/
VMT
ests/vmIOandFlowOperationsTest.json"
RunVmTest
(
fn
,
t
)
}
func
TestPushDupSwap
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmPushDupSwapTest.json"
const
fn
=
"../files/
VMT
ests/vmPushDupSwapTest.json"
RunVmTest
(
fn
,
t
)
}
func
TestVMSha3
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmSha3Test.json"
const
fn
=
"../files/
VMT
ests/vmSha3Test.json"
RunVmTest
(
fn
,
t
)
}
func
TestVm
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmtests.json"
const
fn
=
"../files/
VMT
ests/vmtests.json"
RunVmTest
(
fn
,
t
)
}
func
TestVmLog
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmLogTest.json"
const
fn
=
"../files/
VMT
ests/vmLogTest.json"
RunVmTest
(
fn
,
t
)
}
...
...
vm/vm_jit.go
View file @
8c99a87a
// +build evmjit
package
vm
import
"math/big"
/*
void* evmjit_create();
int evmjit_run(void* _jit, void* _data, void* _env);
void evmjit_destroy(void* _jit);
// Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib
// More: https://github.com/ethereum/evmjit
#cgo LDFLAGS: -levmjit
*/
import
"C"
import
(
"bytes"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/state"
"math/big"
"unsafe"
)
type
JitVm
struct
{
env
Environment
backup
*
Vm
env
Environment
me
ContextRef
callerAddr
[]
byte
price
*
big
.
Int
data
RuntimeData
}
type
i256
[
32
]
byte
type
RuntimeData
struct
{
gas
int64
gasPrice
int64
callData
*
byte
callDataSize
uint64
address
i256
caller
i256
origin
i256
callValue
i256
coinBase
i256
difficulty
i256
gasLimit
i256
number
uint64
timestamp
int64
code
*
byte
codeSize
uint64
}
func
hash2llvm
(
h
[]
byte
)
i256
{
var
m
i256
copy
(
m
[
len
(
m
)
-
len
(
h
)
:
],
h
)
// right aligned copy
return
m
}
func
llvm2hash
(
m
*
i256
)
[]
byte
{
return
C
.
GoBytes
(
unsafe
.
Pointer
(
m
),
C
.
int
(
len
(
m
)))
}
func
llvm2hashRef
(
m
*
i256
)
[]
byte
{
return
(
*
[
1
<<
30
]
byte
)(
unsafe
.
Pointer
(
m
))[
:
len
(
m
)
:
len
(
m
)]
}
func
address2llvm
(
addr
[]
byte
)
i256
{
n
:=
hash2llvm
(
addr
)
bswap
(
&
n
)
return
n
}
// bswap swap bytes of the 256-bit integer on LLVM side
// TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations
func
bswap
(
m
*
i256
)
*
i256
{
for
i
,
l
:=
0
,
len
(
m
);
i
<
l
/
2
;
i
++
{
m
[
i
],
m
[
l
-
i
-
1
]
=
m
[
l
-
i
-
1
],
m
[
i
]
}
return
m
}
func
trim
(
m
[]
byte
)
[]
byte
{
skip
:=
0
for
i
:=
0
;
i
<
len
(
m
);
i
++
{
if
m
[
i
]
==
0
{
skip
++
}
else
{
break
}
}
return
m
[
skip
:
]
}
func
getDataPtr
(
m
[]
byte
)
*
byte
{
var
p
*
byte
if
len
(
m
)
>
0
{
p
=
&
m
[
0
]
}
return
p
}
func
big2llvm
(
n
*
big
.
Int
)
i256
{
m
:=
hash2llvm
(
n
.
Bytes
())
bswap
(
&
m
)
return
m
}
func
llvm2big
(
m
*
i256
)
*
big
.
Int
{
n
:=
big
.
NewInt
(
0
)
for
i
:=
0
;
i
<
len
(
m
);
i
++
{
b
:=
big
.
NewInt
(
int64
(
m
[
i
]))
b
.
Lsh
(
b
,
uint
(
i
)
*
8
)
n
.
Add
(
n
,
b
)
}
return
n
}
// llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC)
// User must asure that referenced memory is available to Go until the data is copied or not needed any more
func
llvm2bytesRef
(
data
*
byte
,
length
uint64
)
[]
byte
{
if
length
==
0
{
return
nil
}
if
data
==
nil
{
panic
(
"Unexpected nil data pointer"
)
}
return
(
*
[
1
<<
30
]
byte
)(
unsafe
.
Pointer
(
data
))[
:
length
:
length
]
}
func
untested
(
condition
bool
,
message
string
)
{
if
condition
{
panic
(
"Condition `"
+
message
+
"` tested. Remove assert."
)
}
}
func
assert
(
condition
bool
,
message
string
)
{
if
!
condition
{
panic
(
"Assert `"
+
message
+
"` failed!"
)
}
}
func
NewJitVm
(
env
Environment
)
*
JitVm
{
backupVm
:=
New
(
env
)
return
&
JitVm
{
env
:
env
,
backup
:
backupVm
}
return
&
JitVm
{
env
:
env
}
}
func
(
self
*
JitVm
)
Run
(
me
,
caller
ContextRef
,
code
[]
byte
,
value
,
gas
,
price
*
big
.
Int
,
callData
[]
byte
)
(
ret
[]
byte
,
err
error
)
{
return
self
.
backup
.
Run
(
me
,
caller
,
code
,
value
,
gas
,
price
,
callData
)
// TODO: depth is increased but never checked by VM. VM should not know about it at all.
self
.
env
.
SetDepth
(
self
.
env
.
Depth
()
+
1
)
// TODO: Move it to Env.Call() or sth
if
Precompiled
[
string
(
me
.
Address
())]
!=
nil
{
// if it's address of precopiled contract
// fallback to standard VM
stdVm
:=
New
(
self
.
env
)
return
stdVm
.
Run
(
me
,
caller
,
code
,
value
,
gas
,
price
,
callData
)
}
if
self
.
me
!=
nil
{
panic
(
"JitVm.Run() can be called only once per JitVm instance"
)
}
self
.
me
=
me
self
.
callerAddr
=
caller
.
Address
()
self
.
price
=
price
self
.
data
.
gas
=
gas
.
Int64
()
self
.
data
.
gasPrice
=
price
.
Int64
()
self
.
data
.
callData
=
getDataPtr
(
callData
)
self
.
data
.
callDataSize
=
uint64
(
len
(
callData
))
self
.
data
.
address
=
address2llvm
(
self
.
me
.
Address
())
self
.
data
.
caller
=
address2llvm
(
caller
.
Address
())
self
.
data
.
origin
=
address2llvm
(
self
.
env
.
Origin
())
self
.
data
.
callValue
=
big2llvm
(
value
)
self
.
data
.
coinBase
=
address2llvm
(
self
.
env
.
Coinbase
())
self
.
data
.
difficulty
=
big2llvm
(
self
.
env
.
Difficulty
())
self
.
data
.
gasLimit
=
big2llvm
(
self
.
env
.
GasLimit
())
self
.
data
.
number
=
self
.
env
.
BlockNumber
()
.
Uint64
()
self
.
data
.
timestamp
=
self
.
env
.
Time
()
self
.
data
.
code
=
getDataPtr
(
code
)
self
.
data
.
codeSize
=
uint64
(
len
(
code
))
jit
:=
C
.
evmjit_create
()
retCode
:=
C
.
evmjit_run
(
jit
,
unsafe
.
Pointer
(
&
self
.
data
),
unsafe
.
Pointer
(
self
))
if
retCode
<
0
{
err
=
errors
.
New
(
"OOG from JIT"
)
gas
.
SetInt64
(
0
)
// Set gas to 0, JIT does not bother
}
else
{
gas
.
SetInt64
(
self
.
data
.
gas
)
if
retCode
==
1
{
// RETURN
ret
=
C
.
GoBytes
(
unsafe
.
Pointer
(
self
.
data
.
callData
),
C
.
int
(
self
.
data
.
callDataSize
))
}
else
if
retCode
==
2
{
// SUICIDE
// TODO: Suicide support logic should be moved to Env to be shared by VM implementations
state
:=
self
.
Env
()
.
State
()
receiverAddr
:=
llvm2hashRef
(
bswap
(
&
self
.
data
.
address
))
receiver
:=
state
.
GetOrNewStateObject
(
receiverAddr
)
balance
:=
state
.
GetBalance
(
me
.
Address
())
receiver
.
AddAmount
(
balance
)
state
.
Delete
(
me
.
Address
())
}
}
C
.
evmjit_destroy
(
jit
);
return
}
func
(
self
*
JitVm
)
Printf
(
format
string
,
v
...
interface
{})
VirtualMachine
{
return
self
.
backup
.
Printf
(
format
,
v
)
return
self
}
func
(
self
*
JitVm
)
Endl
()
VirtualMachine
{
return
self
.
backup
.
Endl
()
return
self
}
func
(
self
*
JitVm
)
Env
()
Environment
{
return
self
.
env
}
//go is nice
//export env_sha3
func
env_sha3
(
dataPtr
*
byte
,
length
uint64
,
resultPtr
unsafe
.
Pointer
)
{
data
:=
llvm2bytesRef
(
dataPtr
,
length
)
hash
:=
crypto
.
Sha3
(
data
)
result
:=
(
*
i256
)(
resultPtr
)
*
result
=
hash2llvm
(
hash
)
}
//export env_sstore
func
env_sstore
(
vmPtr
unsafe
.
Pointer
,
indexPtr
unsafe
.
Pointer
,
valuePtr
unsafe
.
Pointer
)
{
vm
:=
(
*
JitVm
)(
vmPtr
)
index
:=
llvm2hash
(
bswap
((
*
i256
)(
indexPtr
)))
value
:=
llvm2hash
(
bswap
((
*
i256
)(
valuePtr
)))
value
=
trim
(
value
)
if
len
(
value
)
==
0
{
prevValue
:=
vm
.
env
.
State
()
.
GetState
(
vm
.
me
.
Address
(),
index
)
if
len
(
prevValue
)
!=
0
{
vm
.
Env
()
.
State
()
.
Refund
(
vm
.
callerAddr
,
GasSStoreRefund
)
}
}
vm
.
env
.
State
()
.
SetState
(
vm
.
me
.
Address
(),
index
,
value
)
}
//export env_sload
func
env_sload
(
vmPtr
unsafe
.
Pointer
,
indexPtr
unsafe
.
Pointer
,
resultPtr
unsafe
.
Pointer
)
{
vm
:=
(
*
JitVm
)(
vmPtr
)
index
:=
llvm2hash
(
bswap
((
*
i256
)(
indexPtr
)))
value
:=
vm
.
env
.
State
()
.
GetState
(
vm
.
me
.
Address
(),
index
)
result
:=
(
*
i256
)(
resultPtr
)
*
result
=
hash2llvm
(
value
)
bswap
(
result
)
}
//export env_balance
func
env_balance
(
_vm
unsafe
.
Pointer
,
_addr
unsafe
.
Pointer
,
_result
unsafe
.
Pointer
)
{
vm
:=
(
*
JitVm
)(
_vm
)
addr
:=
llvm2hash
((
*
i256
)(
_addr
))
balance
:=
vm
.
Env
()
.
State
()
.
GetBalance
(
addr
)
result
:=
(
*
i256
)(
_result
)
*
result
=
big2llvm
(
balance
)
}
//export env_blockhash
func
env_blockhash
(
_vm
unsafe
.
Pointer
,
_number
unsafe
.
Pointer
,
_result
unsafe
.
Pointer
)
{
vm
:=
(
*
JitVm
)(
_vm
)
number
:=
llvm2big
((
*
i256
)(
_number
))
result
:=
(
*
i256
)(
_result
)
currNumber
:=
vm
.
Env
()
.
BlockNumber
()
limit
:=
big
.
NewInt
(
0
)
.
Sub
(
currNumber
,
big
.
NewInt
(
256
))
if
number
.
Cmp
(
limit
)
>=
0
&&
number
.
Cmp
(
currNumber
)
<
0
{
hash
:=
vm
.
Env
()
.
GetHash
(
uint64
(
number
.
Int64
()))
*
result
=
hash2llvm
(
hash
)
}
else
{
*
result
=
i256
{}
}
}
//export env_call
func
env_call
(
_vm
unsafe
.
Pointer
,
_gas
unsafe
.
Pointer
,
_receiveAddr
unsafe
.
Pointer
,
_value
unsafe
.
Pointer
,
inDataPtr
unsafe
.
Pointer
,
inDataLen
uint64
,
outDataPtr
*
byte
,
outDataLen
uint64
,
_codeAddr
unsafe
.
Pointer
)
bool
{
vm
:=
(
*
JitVm
)(
_vm
)
//fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
fmt
.
Printf
(
"Recovered in env_call (depth %d, out %p %d): %s
\n
"
,
vm
.
Env
()
.
Depth
(),
outDataPtr
,
outDataLen
,
r
)
}
}()
balance
:=
vm
.
Env
()
.
State
()
.
GetBalance
(
vm
.
me
.
Address
())
value
:=
llvm2big
((
*
i256
)(
_value
))
if
balance
.
Cmp
(
value
)
>=
0
{
receiveAddr
:=
llvm2hash
((
*
i256
)(
_receiveAddr
))
inData
:=
C
.
GoBytes
(
inDataPtr
,
C
.
int
(
inDataLen
))
outData
:=
llvm2bytesRef
(
outDataPtr
,
outDataLen
)
codeAddr
:=
llvm2hash
((
*
i256
)(
_codeAddr
))
llvmGas
:=
(
*
i256
)(
_gas
)
gas
:=
llvm2big
(
llvmGas
)
var
out
[]
byte
var
err
error
if
bytes
.
Equal
(
codeAddr
,
receiveAddr
)
{
out
,
err
=
vm
.
env
.
Call
(
vm
.
me
,
codeAddr
,
inData
,
gas
,
vm
.
price
,
value
)
}
else
{
out
,
err
=
vm
.
env
.
CallCode
(
vm
.
me
,
codeAddr
,
inData
,
gas
,
vm
.
price
,
value
)
}
*
llvmGas
=
big2llvm
(
gas
)
if
err
==
nil
{
copy
(
outData
,
out
)
return
true
}
}
return
false
}
//export env_create
func
env_create
(
_vm
unsafe
.
Pointer
,
_gas
unsafe
.
Pointer
,
_value
unsafe
.
Pointer
,
initDataPtr
unsafe
.
Pointer
,
initDataLen
uint64
,
_result
unsafe
.
Pointer
)
{
vm
:=
(
*
JitVm
)(
_vm
)
value
:=
llvm2big
((
*
i256
)(
_value
))
initData
:=
C
.
GoBytes
(
initDataPtr
,
C
.
int
(
initDataLen
))
// TODO: Unnecessary if low balance
result
:=
(
*
i256
)(
_result
)
*
result
=
i256
{}
llvmGas
:=
(
*
i256
)(
_gas
)
gas
:=
llvm2big
(
llvmGas
)
ret
,
suberr
,
ref
:=
vm
.
env
.
Create
(
vm
.
me
,
nil
,
initData
,
gas
,
vm
.
price
,
value
)
if
suberr
==
nil
{
dataGas
:=
big
.
NewInt
(
int64
(
len
(
ret
)))
// TODO: Nto the best design. env.Create can do it, it has the reference to gas counter
dataGas
.
Mul
(
dataGas
,
GasCreateByte
)
gas
.
Sub
(
gas
,
dataGas
)
*
result
=
hash2llvm
(
ref
.
Address
())
}
*
llvmGas
=
big2llvm
(
gas
)
}
//export env_log
func
env_log
(
_vm
unsafe
.
Pointer
,
dataPtr
unsafe
.
Pointer
,
dataLen
uint64
,
_topic1
unsafe
.
Pointer
,
_topic2
unsafe
.
Pointer
,
_topic3
unsafe
.
Pointer
,
_topic4
unsafe
.
Pointer
)
{
vm
:=
(
*
JitVm
)(
_vm
)
data
:=
C
.
GoBytes
(
dataPtr
,
C
.
int
(
dataLen
))
topics
:=
make
([][]
byte
,
0
,
4
)
if
_topic1
!=
nil
{
topics
=
append
(
topics
,
llvm2hash
((
*
i256
)(
_topic1
)))
}
if
_topic2
!=
nil
{
topics
=
append
(
topics
,
llvm2hash
((
*
i256
)(
_topic2
)))
}
if
_topic3
!=
nil
{
topics
=
append
(
topics
,
llvm2hash
((
*
i256
)(
_topic3
)))
}
if
_topic4
!=
nil
{
topics
=
append
(
topics
,
llvm2hash
((
*
i256
)(
_topic4
)))
}
vm
.
Env
()
.
AddLog
(
state
.
NewLog
(
vm
.
me
.
Address
(),
topics
,
data
))
}
//export env_extcode
func
env_extcode
(
_vm
unsafe
.
Pointer
,
_addr
unsafe
.
Pointer
,
o_size
*
uint64
)
*
byte
{
vm
:=
(
*
JitVm
)(
_vm
)
addr
:=
llvm2hash
((
*
i256
)(
_addr
))
code
:=
vm
.
Env
()
.
State
()
.
GetCode
(
addr
)
*
o_size
=
uint64
(
len
(
code
))
return
getDataPtr
(
code
)
}
vm/vm_jit_fake.go
0 → 100644
View file @
8c99a87a
// +build !evmjit
package
vm
import
"fmt"
func
NewJitVm
(
env
Environment
)
VirtualMachine
{
fmt
.
Printf
(
"Warning! EVM JIT not enabled.
\n
"
)
return
New
(
env
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment