-
Notifications
You must be signed in to change notification settings - Fork 80
/
trap.go
206 lines (182 loc) · 5.26 KB
/
trap.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package wasmtime
// #include <stdlib.h>
// #include <wasm.h>
// #include <wasmtime.h>
import "C"
import (
"runtime"
"unsafe"
)
// Trap is the trap instruction which represents the occurrence of a trap.
// Traps are bubbled up through nested instruction sequences, ultimately reducing the entire program to a single trap instruction, signalling abrupt termination.
type Trap struct {
_ptr *C.wasm_trap_t
}
// Frame is one of activation frames which carry the return arity n of the respective function,
// hold the values of its locals (including arguments) in the order corresponding to their static local indices,
// and a reference to the function’s own module instance
type Frame struct {
_ptr *C.wasm_frame_t
_owner interface{}
}
// TrapCode is the code of an instruction trap.
type TrapCode uint8
const (
// StackOverflow: the current stack space was exhausted.
StackOverflow TrapCode = iota
// MemoryOutOfBounds: out-of-bounds memory access.
MemoryOutOfBounds
// HeapMisaligned: a wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
HeapMisaligned
// TableOutOfBounds: out-of-bounds access to a table.
TableOutOfBounds
// IndirectCallToNull: indirect call to a null table entry.
IndirectCallToNull
// BadSignature: signature mismatch on indirect call.
BadSignature
// IntegerOverflow: an integer arithmetic operation caused an overflow.
IntegerOverflow
// IntegerDivisionByZero: integer division by zero.
IntegerDivisionByZero
// BadConversionToInteger: failed float-to-int conversion.
BadConversionToInteger
// UnreachableCodeReached: code that was supposed to have been unreachable was reached.
UnreachableCodeReached
// Interrupt: execution has been interrupted.
Interrupt
// OutOfFuel: Execution has run out of the configured fuel amount.
OutOfFuel
)
// NewTrap creates a new `Trap` with the `name` and the type provided.
func NewTrap(message string) *Trap {
ptr := C.wasmtime_trap_new(C._GoStringPtr(message), C._GoStringLen(message))
runtime.KeepAlive(message)
return mkTrap(ptr)
}
func mkTrap(ptr *C.wasm_trap_t) *Trap {
trap := &Trap{_ptr: ptr}
runtime.SetFinalizer(trap, func(trap *Trap) {
C.wasm_trap_delete(trap._ptr)
})
return trap
}
func (t *Trap) ptr() *C.wasm_trap_t {
ret := t._ptr
if ret == nil {
panic("object has been closed already")
}
maybeGC()
return ret
}
// Close will deallocate this type's state explicitly.
//
// For more information see the documentation for engine.Close()
func (t *Trap) Close() {
if t._ptr == nil {
return
}
runtime.SetFinalizer(t, nil)
C.wasm_trap_delete(t._ptr)
t._ptr = nil
}
// Message returns the message of the `Trap`
func (t *Trap) Message() string {
message := C.wasm_byte_vec_t{}
C.wasm_trap_message(t.ptr(), &message)
ret := C.GoStringN(message.data, C.int(message.size-1))
runtime.KeepAlive(t)
C.wasm_byte_vec_delete(&message)
return ret
}
// Code returns the code of the `Trap` if it exists, nil otherwise.
func (t *Trap) Code() *TrapCode {
var code C.uint8_t
var ret *TrapCode
ok := C.wasmtime_trap_code(t.ptr(), &code)
if ok == C._Bool(true) {
ret = (*TrapCode)(&code)
}
runtime.KeepAlive(t)
return ret
}
func (t *Trap) Error() string {
return t.Message()
}
func unwrapStrOr(s *string, other string) string {
if s == nil {
return other
}
return *s
}
type frameList struct {
vec C.wasm_frame_vec_t
owner interface{}
}
// Frames returns the wasm function frames that make up this trap
func (t *Trap) Frames() []*Frame {
frames := &frameList{owner: t}
C.wasm_trap_trace(t.ptr(), &frames.vec)
runtime.KeepAlive(t)
runtime.SetFinalizer(frames, func(frames *frameList) {
C.wasm_frame_vec_delete(&frames.vec)
})
ret := make([]*Frame, int(frames.vec.size))
base := unsafe.Pointer(frames.vec.data)
var ptr *C.wasm_frame_t
for i := 0; i < int(frames.vec.size); i++ {
ptr := *(**C.wasm_frame_t)(unsafe.Pointer(uintptr(base) + unsafe.Sizeof(ptr)*uintptr(i)))
ret[i] = &Frame{
_ptr: ptr,
_owner: frames,
}
}
return ret
}
func (f *Frame) ptr() *C.wasm_frame_t {
ret := f._ptr
if ret == nil {
panic("object has been closed already")
}
maybeGC()
return ret
}
// FuncIndex returns the function index in the wasm module that this frame represents
func (f *Frame) FuncIndex() uint32 {
ret := C.wasm_frame_func_index(f.ptr())
runtime.KeepAlive(f)
return uint32(ret)
}
// FuncName returns the name, if available, for this frame's function
func (f *Frame) FuncName() *string {
ret := C.wasmtime_frame_func_name(f.ptr())
if ret == nil {
runtime.KeepAlive(f)
return nil
}
str := C.GoStringN(ret.data, C.int(ret.size))
runtime.KeepAlive(f)
return &str
}
// ModuleName returns the name, if available, for this frame's module
func (f *Frame) ModuleName() *string {
ret := C.wasmtime_frame_module_name(f.ptr())
if ret == nil {
runtime.KeepAlive(f)
return nil
}
str := C.GoStringN(ret.data, C.int(ret.size))
runtime.KeepAlive(f)
return &str
}
// ModuleOffset returns offset of this frame's instruction into the original module
func (f *Frame) ModuleOffset() uint {
ret := uint(C.wasm_frame_module_offset(f.ptr()))
runtime.KeepAlive(f)
return ret
}
// FuncOffset returns offset of this frame's instruction into the original function
func (f *Frame) FuncOffset() uint {
ret := uint(C.wasm_frame_func_offset(f.ptr()))
runtime.KeepAlive(f)
return ret
}