-
Notifications
You must be signed in to change notification settings - Fork 4
/
compiled_vm.go
132 lines (114 loc) · 3.32 KB
/
compiled_vm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package exec
import (
"bytes"
"errors"
"fmt"
"github.com/PhoenixGlobal/Phoenix-Chain-Core/libs/wagon/disasm"
"github.com/PhoenixGlobal/Phoenix-Chain-Core/libs/wagon/exec/internal/compile"
"github.com/PhoenixGlobal/Phoenix-Chain-Core/libs/wagon/wasm"
"sync"
)
type CompileVM struct {
VM
}
type CompiledModule struct {
RawModule *wasm.Module
globals []uint64
memory []byte
funcs []function
}
func CompileModule(module *wasm.Module) (*CompiledModule, error) {
var compiled CompiledModule
if module.Memory != nil && len(module.Memory.Entries) != 0 {
if len(module.Memory.Entries) > 1 {
return nil, ErrMultipleLinearMemories
}
memsize := uint(module.Memory.Entries[0].Limits.Initial) * wasmPageSize
compiled.memory = make([]byte, memsize)
copy(compiled.memory, module.LinearMemoryIndexSpace[0])
}
compiled.funcs = make([]function, len(module.FunctionIndexSpace))
compiled.globals = make([]uint64, len(module.GlobalIndexSpace))
compiled.RawModule = module
nNatives := 0
for i, fn := range module.FunctionIndexSpace {
// Skip native methods as they need not be
// disassembled; simply add them at the end
// of the `funcs` array as is, as specified
// in the spec. See the "host functions"
// section of:
// https://webassembly.github.io/spec/core/exec/modules.html#allocation
if fn.IsHost() {
compiled.funcs[i] = goFunction{
typ: fn.Host.Type(),
val: fn.Host,
}
nNatives++
continue
}
disassembly, err := disasm.NewDisassembly(fn, module)
if err != nil {
return nil, err
}
totalLocalVars := 0
totalLocalVars += len(fn.Sig.ParamTypes)
for _, entry := range fn.Body.Locals {
totalLocalVars += int(entry.Count)
}
code, meta := compile.Compile(disassembly.Code)
compiled.funcs[i] = compiledFunction{
code: code,
branchTables: meta.BranchTables,
maxDepth: disassembly.MaxDepth,
totalLocalVars: totalLocalVars,
args: len(fn.Sig.ParamTypes),
returns: len(fn.Sig.ReturnTypes) != 0,
}
}
for i, global := range module.GlobalIndexSpace {
val, err := module.ExecInitExpr(global.Init)
if err != nil {
return nil, err
}
switch v := val.(type) {
case int32:
compiled.globals[i] = uint64(v)
case int64:
compiled.globals[i] = uint64(v)
//case float32:
// compiled.globals[i] = uint64(math.Float32bits(v))
//case float64:
// compiled.globals[i] = uint64(math.Float64bits(v))
}
}
if module.Start != nil {
//_, err := compiled.ExecCode(int64(module.Start.Index))
//if err != nil {
// return nil, err
//}
return nil, errors.New("start entry is not supported in smart contract")
}
return &compiled, nil
}
var memoryPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
func NewVMWithCompiled(module *CompiledModule, memLimit uint64) (*CompileVM, error) {
var vm CompileVM
memsize := len(module.memory)
if uint64(memsize) > memLimit {
return nil, fmt.Errorf("memory is exceed the limitation of %d", memLimit)
}
vm.MemoryLimitation = memLimit
membuf := memoryPool.Get().(*bytes.Buffer)
membuf.Reset()
membuf.Write(module.memory)
vm.memory = membuf.Bytes()
vm.membuf = membuf
vm.funcs = module.funcs
vm.globals = make([]uint64, len(module.RawModule.GlobalIndexSpace))
copy(vm.globals, module.globals)
vm.newFuncTable()
vm.module = module.RawModule
return &vm, nil
}