good morning!!!!
Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
B
bor
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Harbor Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
github
maticnetwork
bor
Commits
8c99a87a
Commit
8c99a87a
authored
10 years ago
by
Jeffrey Wilcke
Browse files
Options
Downloads
Plain Diff
Merge branch 'chfast-pr/evmjit' into develop
parents
48083608
fe14b0b8
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
.gitignore
+2
-0
2 additions, 0 deletions
.gitignore
tests/vm/gh_test.go
+9
-9
9 additions, 9 deletions
tests/vm/gh_test.go
vm/vm_jit.go
+349
-9
349 additions, 9 deletions
vm/vm_jit.go
vm/vm_jit_fake.go
+10
-0
10 additions, 0 deletions
vm/vm_jit_fake.go
with
370 additions
and
18 deletions
.gitignore
+
2
−
0
View file @
8c99a87a
...
@@ -15,3 +15,5 @@
...
@@ -15,3 +15,5 @@
.#*
.#*
*#
*#
*~
*~
.project
.settings
This diff is collapsed.
Click to expand it.
tests/vm/gh_test.go
+
9
−
9
View file @
8c99a87a
...
@@ -172,47 +172,47 @@ func RunVmTest(p string, t *testing.T) {
...
@@ -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.
// 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
)
{
func
TestVMArithmetic
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmArithmeticTest.json"
const
fn
=
"../files/
VMT
ests/vmArithmeticTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestBitwiseLogicOperation
(
t
*
testing
.
T
)
{
func
TestBitwiseLogicOperation
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmBitwiseLogicOperationTest.json"
const
fn
=
"../files/
VMT
ests/vmBitwiseLogicOperationTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestBlockInfo
(
t
*
testing
.
T
)
{
func
TestBlockInfo
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmBlockInfoTest.json"
const
fn
=
"../files/
VMT
ests/vmBlockInfoTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestEnvironmentalInfo
(
t
*
testing
.
T
)
{
func
TestEnvironmentalInfo
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmEnvironmentalInfoTest.json"
const
fn
=
"../files/
VMT
ests/vmEnvironmentalInfoTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestFlowOperation
(
t
*
testing
.
T
)
{
func
TestFlowOperation
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmIOandFlowOperationsTest.json"
const
fn
=
"../files/
VMT
ests/vmIOandFlowOperationsTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestPushDupSwap
(
t
*
testing
.
T
)
{
func
TestPushDupSwap
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmPushDupSwapTest.json"
const
fn
=
"../files/
VMT
ests/vmPushDupSwapTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestVMSha3
(
t
*
testing
.
T
)
{
func
TestVMSha3
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmSha3Test.json"
const
fn
=
"../files/
VMT
ests/vmSha3Test.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestVm
(
t
*
testing
.
T
)
{
func
TestVm
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmtests.json"
const
fn
=
"../files/
VMT
ests/vmtests.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
func
TestVmLog
(
t
*
testing
.
T
)
{
func
TestVmLog
(
t
*
testing
.
T
)
{
const
fn
=
"../files/
vmt
ests/vmLogTest.json"
const
fn
=
"../files/
VMT
ests/vmLogTest.json"
RunVmTest
(
fn
,
t
)
RunVmTest
(
fn
,
t
)
}
}
...
...
This diff is collapsed.
Click to expand it.
vm/vm_jit.go
+
349
−
9
View file @
8c99a87a
// +build evmjit
package
vm
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
{
type
JitVm
struct
{
env
Environment
env
Environment
backup
*
Vm
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
{
func
NewJitVm
(
env
Environment
)
*
JitVm
{
backupVm
:=
New
(
env
)
return
&
JitVm
{
env
:
env
}
return
&
JitVm
{
env
:
env
,
backup
:
backupVm
}
}
}
func
(
self
*
JitVm
)
Run
(
me
,
caller
ContextRef
,
code
[]
byte
,
value
,
gas
,
price
*
big
.
Int
,
callData
[]
byte
)
(
ret
[]
byte
,
err
error
)
{
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
{
func
(
self
*
JitVm
)
Printf
(
format
string
,
v
...
interface
{})
VirtualMachine
{
return
self
.
backup
.
Printf
(
format
,
v
)
return
self
}
}
func
(
self
*
JitVm
)
Endl
()
VirtualMachine
{
func
(
self
*
JitVm
)
Endl
()
VirtualMachine
{
return
self
.
backup
.
Endl
()
return
self
}
}
func
(
self
*
JitVm
)
Env
()
Environment
{
func
(
self
*
JitVm
)
Env
()
Environment
{
return
self
.
env
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
)
}
This diff is collapsed.
Click to expand it.
vm/vm_jit_fake.go
0 → 100644
+
10
−
0
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
)
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment