Skip to content
This repository was archived by the owner on May 11, 2020. It is now read-only.

Commit cbbdf08

Browse files
carltravelersbinet
authored andcommitted
all: fine tune exec module code
* fine tune exec module code. and else/end opcode should not discard any stack item, need not add unreachable instruction to instr stream to compile * refine code, and add uint test
1 parent 1e64ad3 commit cbbdf08

File tree

6 files changed

+237
-122
lines changed

6 files changed

+237
-122
lines changed

disasm/disasm.go

Lines changed: 64 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
107107
stackDepths.Push(0)
108108
blockIndices := &stack.Stack{} // a stack of indices to operators which start new blocks
109109
curIndex := 0
110-
var lastOpReturn bool
111110

112111
for _, instr := range instrs {
113112
logger.Printf("stack top is %d", stackDepths.Top())
@@ -129,13 +128,28 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
129128
instr.Unreachable = !isInstrReachable(blockPolymorphicOps)
130129
}
131130

131+
var blockStartIndex uint64
132+
switch op {
133+
case ops.End, ops.Else:
134+
blockStartIndex = blockIndices.Pop()
135+
if op == ops.Else {
136+
blockIndices.Push(uint64(curIndex))
137+
}
138+
case ops.Block, ops.Loop, ops.If:
139+
blockIndices.Push(uint64(curIndex))
140+
}
141+
142+
if instr.Unreachable {
143+
continue
144+
}
145+
132146
logger.Printf("op: %s, unreachable: %v", opStr.Name, instr.Unreachable)
133-
if !opStr.Polymorphic && !instr.Unreachable {
147+
if !opStr.Polymorphic {
134148
top := int(stackDepths.Top())
135149
top -= len(opStr.Args)
136150
stackDepths.SetTop(uint64(top))
137-
if top < -1 {
138-
return nil, ErrStackUnderflow
151+
if top < 0 {
152+
panic("underflow during validation")
139153
}
140154
if opStr.Returns != wasm.ValueType(wasm.BlockTypeEmpty) {
141155
top++
@@ -148,23 +162,13 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
148162
case ops.Unreachable:
149163
pushPolymorphicOp(blockPolymorphicOps, curIndex)
150164
case ops.Drop:
151-
if !instr.Unreachable {
152-
stackDepths.SetTop(stackDepths.Top() - 1)
153-
}
165+
stackDepths.SetTop(stackDepths.Top() - 1)
154166
case ops.Select:
155-
if !instr.Unreachable {
156-
stackDepths.SetTop(stackDepths.Top() - 2)
157-
}
167+
stackDepths.SetTop(stackDepths.Top() - 2)
158168
case ops.Return:
159-
if !instr.Unreachable {
160-
stackDepths.SetTop(stackDepths.Top() - uint64(len(fn.Sig.ReturnTypes)))
161-
}
169+
stackDepths.SetTop(stackDepths.Top() - uint64(len(fn.Sig.ReturnTypes)))
162170
pushPolymorphicOp(blockPolymorphicOps, curIndex)
163-
lastOpReturn = true
164171
case ops.End, ops.Else:
165-
// The max depth reached while execing the current block
166-
curDepth := stackDepths.Top()
167-
blockStartIndex := blockIndices.Pop()
168172
blockSig := disas.Code[blockStartIndex].Block.Signature
169173
instr.Block = &BlockInfo{
170174
Start: false,
@@ -175,7 +179,7 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
175179
disas.Code[blockStartIndex].Block.EndIndex = curIndex
176180
} else { // ops.Else
177181
instr.Block.ElseIfIndex = int(blockStartIndex)
178-
disas.Code[blockStartIndex].Block.IfElseIndex = int(blockStartIndex)
182+
disas.Code[blockStartIndex].Block.IfElseIndex = int(curIndex)
179183
}
180184

181185
// The max depth reached while execing the last block
@@ -187,60 +191,28 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
187191
prevDepthIndex := stackDepths.Len() - 2
188192
prevDepth := stackDepths.Get(prevDepthIndex)
189193

190-
if op != ops.Else && blockSig != wasm.BlockTypeEmpty && !instr.Unreachable {
194+
if op != ops.Else && blockSig != wasm.BlockTypeEmpty {
191195
stackDepths.Set(prevDepthIndex, prevDepth+1)
192196
disas.checkMaxDepth(int(stackDepths.Get(prevDepthIndex)))
193197
}
194198

195-
if !lastOpReturn {
196-
elemsDiscard := int(curDepth) - int(prevDepth)
197-
if elemsDiscard < -1 {
198-
return nil, ErrStackUnderflow
199-
}
200-
instr.NewStack = &StackInfo{
201-
StackTopDiff: int64(elemsDiscard),
202-
PreserveTop: blockSig != wasm.BlockTypeEmpty,
203-
}
204-
logger.Printf("discard %d elements, preserve top: %v", elemsDiscard, instr.NewStack.PreserveTop)
205-
} else {
206-
instr.NewStack = &StackInfo{}
207-
}
208-
209199
logger.Printf("setting new stack for %s block (%d)", disas.Code[blockStartIndex].Op.Name, blockStartIndex)
210-
disas.Code[blockStartIndex].NewStack = instr.NewStack
211-
if !instr.Unreachable {
212-
blockPolymorphicOps = blockPolymorphicOps[:len(blockPolymorphicOps)-1]
213-
}
200+
blockPolymorphicOps = blockPolymorphicOps[:len(blockPolymorphicOps)-1]
214201

215202
stackDepths.Pop()
216203
if op == ops.Else {
217204
stackDepths.Push(stackDepths.Top())
218-
blockIndices.Push(uint64(curIndex))
219-
if !instr.Unreachable {
220-
blockPolymorphicOps = append(blockPolymorphicOps, []int{})
221-
}
205+
blockPolymorphicOps = append(blockPolymorphicOps, []int{})
222206
}
223-
224207
case ops.Block, ops.Loop, ops.If:
225208
sig := instr.Immediates[0].(wasm.BlockType)
226209
logger.Printf("if, depth is %d", stackDepths.Top())
227210
stackDepths.Push(stackDepths.Top())
228-
// If this new block is unreachable, its
229-
// entire instruction sequence is unreachable
230-
// as well. To make sure that isInstrReachable
231-
// returns the correct value, we don't push a new
232-
// array to blockPolymorphicOps.
233-
if !instr.Unreachable {
234-
// Therefore, only push a new array if this instruction
235-
// is reachable.
236-
blockPolymorphicOps = append(blockPolymorphicOps, []int{})
237-
}
211+
blockPolymorphicOps = append(blockPolymorphicOps, []int{})
238212
instr.Block = &BlockInfo{
239213
Start: true,
240214
Signature: sig,
241215
}
242-
243-
blockIndices.Push(uint64(curIndex))
244216
case ops.Br, ops.BrIf:
245217
depth := instr.Immediates[0].(uint32)
246218
if int(depth) == blockIndices.Len() {
@@ -260,20 +232,21 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
260232

261233
// No need to subtract 2 here, we are getting the block
262234
// we need to branch to.
263-
index := blockIndices.Get(blockIndices.Len() - 1 - int(depth))
264-
instr.NewStack = &StackInfo{
265-
StackTopDiff: int64(elemsDiscard),
266-
PreserveTop: disas.Code[index].Block.Signature != wasm.BlockTypeEmpty,
235+
// No need Discard one. and PreserveTop.
236+
if elemsDiscard > 1 {
237+
index := blockIndices.Get(blockIndices.Len() - 1 - int(depth))
238+
instr.NewStack = &StackInfo{
239+
StackTopDiff: int64(elemsDiscard),
240+
PreserveTop: disas.Code[index].Block.Signature != wasm.BlockTypeEmpty,
241+
}
267242
}
268243
}
269244
if op == ops.Br {
270245
pushPolymorphicOp(blockPolymorphicOps, curIndex)
271246
}
272247

273248
case ops.BrTable:
274-
if !instr.Unreachable {
275-
stackDepths.SetTop(stackDepths.Top() - 1)
276-
}
249+
stackDepths.SetTop(stackDepths.Top() - 1)
277250
targetCount := instr.Immediates[0].(uint32)
278251
for i := uint32(0); i < targetCount; i++ {
279252
entry := instr.Immediates[i+1].(uint32)
@@ -318,42 +291,40 @@ func NewDisassembly(fn wasm.Function, module *wasm.Module) (*Disassembly, error)
318291
pushPolymorphicOp(blockPolymorphicOps, curIndex)
319292
case ops.Call, ops.CallIndirect:
320293
index := instr.Immediates[0].(uint32)
321-
if !instr.Unreachable {
322-
var sig *wasm.FunctionSig
323-
top := int(stackDepths.Top())
324-
if op == ops.CallIndirect {
325-
if module.Types == nil {
326-
return nil, errors.New("missing types section")
327-
}
328-
sig = &module.Types.Entries[index]
329-
top--
330-
} else {
331-
sig = module.GetFunction(int(index)).Sig
294+
var sig *wasm.FunctionSig
295+
top := int(stackDepths.Top())
296+
297+
switch op {
298+
case ops.CallIndirect:
299+
if module.Types == nil {
300+
return nil, errors.New("missing types section")
332301
}
333-
top -= len(sig.ParamTypes)
334-
top += len(sig.ReturnTypes)
335-
stackDepths.SetTop(uint64(top))
336-
disas.checkMaxDepth(top)
337-
}
338-
case ops.GetLocal, ops.SetLocal, ops.TeeLocal, ops.GetGlobal, ops.SetGlobal:
339-
if !instr.Unreachable {
340-
top := stackDepths.Top()
341-
switch op {
342-
case ops.GetLocal, ops.GetGlobal:
343-
top++
344-
stackDepths.SetTop(top)
345-
disas.checkMaxDepth(int(top))
346-
case ops.SetLocal, ops.SetGlobal:
347-
top--
348-
stackDepths.SetTop(top)
349-
case ops.TeeLocal:
350-
// stack remains unchanged for tee_local
302+
sig = &module.Types.Entries[index]
303+
top--
304+
default:
305+
sig, err = module.GetFunctionSig(index)
306+
if err != nil {
307+
return nil, err
351308
}
352309
}
353-
}
354310

355-
if op != ops.Return {
356-
lastOpReturn = false
311+
top -= len(sig.ParamTypes)
312+
top += len(sig.ReturnTypes)
313+
stackDepths.SetTop(uint64(top))
314+
disas.checkMaxDepth(top)
315+
case ops.GetLocal, ops.SetLocal, ops.TeeLocal, ops.GetGlobal, ops.SetGlobal:
316+
top := stackDepths.Top()
317+
switch op {
318+
case ops.GetLocal, ops.GetGlobal:
319+
top++
320+
stackDepths.SetTop(top)
321+
disas.checkMaxDepth(int(top))
322+
case ops.SetLocal, ops.SetGlobal:
323+
top--
324+
stackDepths.SetTop(top)
325+
case ops.TeeLocal:
326+
// stack remains unchanged for tee_local
327+
}
357328
}
358329

359330
disas.Code = append(disas.Code, instr)

exec/internal/compile/compile.go

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -206,29 +206,15 @@ func Compile(disassembly []disasm.Instr) ([]byte, *BytecodeMetadata) {
206206
offset: int64(buffer.Len()),
207207
ifBlock: false,
208208
loopBlock: true,
209-
discard: *instr.NewStack,
210209
}
211210
continue
212211
case ops.Block:
213212
curBlockDepth++
214213
blocks[curBlockDepth] = &block{
215214
ifBlock: false,
216-
discard: *instr.NewStack,
217215
}
218216
continue
219217
case ops.Else:
220-
ifInstr := disassembly[instr.Block.ElseIfIndex] // the corresponding `if` instruction for this else
221-
if ifInstr.NewStack != nil && ifInstr.NewStack.StackTopDiff != 0 {
222-
// add code for jumping out of a taken if branch
223-
op := OpDiscard
224-
if ifInstr.NewStack.PreserveTop {
225-
op = OpDiscardPreserveTop
226-
}
227-
228-
emitMetadata(op, buffer.Len(), instAndInt64Len)
229-
buffer.WriteByte(op)
230-
binary.Write(buffer, binary.LittleEndian, ifInstr.NewStack.StackTopDiff)
231-
}
232218
emitMetadata(OpJmp, buffer.Len(), instAndInt64Len)
233219
buffer.WriteByte(OpJmp)
234220
ifBlockEndOffset := int64(buffer.Len())
@@ -247,21 +233,6 @@ func Compile(disassembly []disasm.Instr) ([]byte, *BytecodeMetadata) {
247233
depth := curBlockDepth
248234
block := blocks[depth]
249235

250-
if instr.NewStack.StackTopDiff != 0 {
251-
// when exiting a block, discard elements to
252-
// restore stack height.
253-
op := OpDiscard
254-
if instr.NewStack.PreserveTop {
255-
// this is true when the block has a
256-
// signature, and therefore pushes
257-
// a value on to the stack
258-
op = OpDiscardPreserveTop
259-
}
260-
emitMetadata(op, buffer.Len(), instAndInt64Len)
261-
buffer.WriteByte(op)
262-
binary.Write(buffer, binary.LittleEndian, instr.NewStack.StackTopDiff)
263-
}
264-
265236
if !block.loopBlock { // is a normal block
266237
block.offset = int64(buffer.Len())
267238
if block.ifBlock {

wasm/index.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package wasm
66

77
import (
88
"bytes"
9+
"errors"
910
"fmt"
1011
"reflect"
1112
)
@@ -82,6 +83,7 @@ func (m *Module) populateFunctions() error {
8283
}
8384

8485
funcs := make([]uint32, 0, len(m.Function.Types)+len(m.imports.Funcs))
86+
8587
funcs = append(funcs, m.imports.Funcs...)
8688
funcs = append(funcs, m.Function.Types...)
8789
m.Function.Types = funcs
@@ -98,6 +100,36 @@ func (m *Module) GetFunction(i int) *Function {
98100
return &m.FunctionIndexSpace[i]
99101
}
100102

103+
func (m *Module) GetFunctionSig(i uint32) (*FunctionSig, error) {
104+
var funcindex uint32
105+
if m.Import == nil {
106+
if i >= uint32(len(m.Function.Types)) {
107+
return nil, errors.New("fsig out of len")
108+
}
109+
typeindex := m.Function.Types[i]
110+
return &m.Types.Entries[typeindex], nil
111+
}
112+
113+
for _, importEntry := range m.Import.Entries {
114+
if importEntry.Type.Kind() == ExternalFunction {
115+
if funcindex == i {
116+
typeindex := importEntry.Type.(FuncImport).Type
117+
return &m.Types.Entries[typeindex], nil
118+
}
119+
120+
funcindex++
121+
}
122+
}
123+
124+
i = i - (funcindex - uint32(len(m.imports.Funcs)))
125+
if i >= uint32(len(m.Function.Types)) {
126+
return nil, errors.New("fsig out of len")
127+
}
128+
129+
typeindex := m.Function.Types[i]
130+
return &m.Types.Entries[typeindex], nil
131+
}
132+
101133
func (m *Module) populateGlobals() error {
102134
if m.Global == nil {
103135
return nil
@@ -118,6 +150,33 @@ func (m *Module) GetGlobal(i int) *GlobalEntry {
118150
return &m.GlobalIndexSpace[i]
119151
}
120152

153+
func (m *Module) GetGlobalType(i uint32) (*GlobalVar, error) {
154+
var globalindex uint32
155+
156+
if m.Import == nil {
157+
if i >= uint32(len(m.Global.Globals)) {
158+
return nil, errors.New("global index out of len")
159+
}
160+
return &m.Global.Globals[i].Type, nil
161+
}
162+
163+
for _, importEntry := range m.Import.Entries {
164+
if importEntry.Type.Kind() == ExternalGlobal {
165+
if globalindex == i {
166+
v := importEntry.Type.(GlobalVarImport).Type
167+
return &v, nil
168+
}
169+
globalindex++
170+
}
171+
}
172+
173+
i = i - (globalindex - uint32(m.imports.Globals))
174+
if i >= uint32(len(m.Global.Globals)) {
175+
return nil, errors.New("global index out of len")
176+
}
177+
return &m.Global.Globals[i].Type, nil
178+
}
179+
121180
func (m *Module) populateTables() error {
122181
if m.Table == nil || len(m.Table.Entries) == 0 || m.Elements == nil || len(m.Elements.Entries) == 0 {
123182
return nil

0 commit comments

Comments
 (0)