Skip to content

Commit aabaeb7

Browse files
committed
impl: fibonacci
1 parent fc7daac commit aabaeb7

File tree

9 files changed

+370
-19
lines changed

9 files changed

+370
-19
lines changed

source/binary/instruction.d

+22
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
module binary.instruction;
22

3+
import binary.types: Block;
4+
35
import std.sumtype;
46

7+
///
8+
struct If
9+
{
10+
///
11+
Block block;
12+
}
13+
514
///
615
struct End {}
716

17+
///
18+
struct Return {}
19+
820
///
921
struct LocalGet
1022
{
@@ -35,9 +47,15 @@ struct I32Const
3547
int value;
3648
}
3749

50+
///
51+
struct I32LtS {}
52+
3853
///
3954
struct I32Add {}
4055

56+
///
57+
struct I32Sub {}
58+
4159
///
4260
struct Call
4361
{
@@ -46,12 +64,16 @@ struct Call
4664
}
4765

4866
alias Instruction = SumType!(
67+
If,
4968
End,
69+
Return,
5070
LocalGet,
5171
LocalSet,
5272
I32Store,
5373
I32Const,
74+
I32LtS,
5475
I32Add,
76+
I32Sub,
5577
Call,
5678
);
5779

source/binary/mod.d

+99-12
Original file line numberDiff line numberDiff line change
@@ -218,66 +218,97 @@ Function[] decodeCodeSection(ref const(ubyte)[] input)
218218
const count = input.leb128!uint();
219219
foreach (_; 0..count)
220220
{
221-
input.leb128!uint(); // size
222-
functions ~= input.decodeFunctionBody();
221+
auto size = input.leb128!uint(); // func body size
222+
functions ~= input.decodeFunctionBody(size);
223223
}
224224
return functions;
225225
}
226226

227227
///
228-
Function decodeFunctionBody(ref const(ubyte)[] input)
228+
Function decodeFunctionBody(ref const(ubyte)[] input, ref uint remaining)
229229
{
230230
Function body;
231231
const count = input.leb128!uint();
232+
remaining--;
232233
foreach (_; 0..count)
233234
{
234235
auto typeCount = input.leb128!uint();
236+
remaining--;
235237
auto valueType = input.decodeValueSection();
238+
remaining--;
236239
body.locals ~= FunctionLocal(typeCount, valueType);
237240
}
238241

239-
// FIXME: 命令だけconsumeするようにしないといけない
240-
while (input.length)
242+
while (remaining > 0)
241243
{
242-
auto instruction = input.decodeInstruction();
244+
auto instruction = input.decodeInstruction(remaining);
243245
body.code ~= instruction;
244-
if (instruction.isEndInstruction())
245-
{
246-
break;
247-
}
248246
}
249247
return body;
250248
}
251249

252250
///
253-
Instruction decodeInstruction(ref const(ubyte)[] input)
251+
Instruction decodeInstruction(ref const(ubyte)[] input, ref uint remaining)
254252
{
255253
auto op = cast(OpCode) input.read!ubyte();
254+
remaining--;
256255
switch (op)
257256
{
257+
case OpCode.If:
258+
auto block = input.decodeBlockSection(remaining);
259+
return Instruction(If(block));
260+
case OpCode.Return:
261+
return Instruction(Return());
258262
case OpCode.LocalGet:
259263
auto idx = input.leb128!uint();
264+
remaining--;
260265
return Instruction(LocalGet(idx));
261266
case OpCode.LocalSet:
262267
auto idx = input.leb128!uint();
268+
remaining--;
263269
return Instruction(LocalSet(idx));
264270
case OpCode.I32Store:
265271
auto align_ = input.leb128!uint();
266272
auto offset = input.leb128!uint();
273+
remaining -= 2;
267274
return Instruction(I32Store(align_, offset));
268275
case OpCode.I32Const:
269276
auto value = input.leb128!int();
277+
remaining--;
270278
return Instruction(I32Const(value));
279+
case OpCode.I32LtS:
280+
return Instruction(I32LtS());
271281
case OpCode.I32Add:
272282
return Instruction(I32Add());
283+
case OpCode.I32Sub:
284+
return Instruction(I32Sub());
273285
case OpCode.End:
274286
return Instruction(End());
275287
case OpCode.Call:
276288
auto idx = input.leb128!uint();
289+
remaining--;
277290
return Instruction(Call(idx));
278291
default:
279-
assert(false, "invalid opcode");
292+
import std.format : format;
293+
assert(false, op.format!"invalid opcode: %d"());
294+
}
295+
}
296+
297+
///
298+
Block decodeBlockSection(ref const(ubyte)[] input, ref uint remaining)
299+
{
300+
const mark = input.read!ubyte();
301+
remaining--;
302+
BlockType blockType;
303+
if (mark == 0x40)
304+
{
305+
blockType = BlockType(Void());
306+
}
307+
else
308+
{
309+
blockType = BlockType([cast(ValueType) mark]);
280310
}
311+
return Block(blockType: blockType);
281312
}
282313

283314
///
@@ -604,3 +635,59 @@ unittest
604635
assert(actual == expected);
605636
}
606637
}
638+
639+
@("decode fib")
640+
unittest
641+
{
642+
import std.process;
643+
const p = executeShell("wasm-tools parse source/fixtures/fib.wat");
644+
const (ubyte)[] wasm = cast(ubyte[]) p.output;
645+
const actual = decodeModule(wasm);
646+
const Module expected = {
647+
magic: ['\0', 'a', 's', 'm'],
648+
version_: 1,
649+
typeSection: [
650+
{
651+
params: [ValueType.I32],
652+
results: [ValueType.I32]
653+
}
654+
],
655+
functionSection: [0],
656+
codeSection: [
657+
{
658+
locals: [],
659+
code: [
660+
Instruction(LocalGet(0)),
661+
Instruction(I32Const(2)),
662+
Instruction(I32LtS()),
663+
Instruction(
664+
If(Block(BlockType(Void())))
665+
),
666+
Instruction(I32Const(1)),
667+
Instruction(Return()),
668+
Instruction(End()),
669+
Instruction(LocalGet(0)),
670+
Instruction(I32Const(2)),
671+
Instruction(I32Sub()),
672+
Instruction(Call(0)),
673+
Instruction(LocalGet(0)),
674+
Instruction(I32Const(1)),
675+
Instruction(I32Sub()),
676+
Instruction(Call(0)),
677+
Instruction(I32Add()),
678+
Instruction(Return()),
679+
Instruction(End())
680+
]
681+
}
682+
]
683+
,
684+
exportSection: [
685+
Export(
686+
name: "fib",
687+
desc: ExportDesc(Func(0)),
688+
)
689+
],
690+
importSection: []
691+
};
692+
assert(actual == expected);
693+
}

source/binary/opcode.d

+4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ module binary.opcode;
33
///
44
enum OpCode : ubyte
55
{
6+
If = 0x04,
67
End = 0x0B,
8+
Return = 0x0F,
79
LocalGet = 0x20,
810
LocalSet = 0x21,
911
I32Store = 0x36,
1012
I32Const = 0x41,
13+
I32LtS = 0x48,
1114
I32Add = 0x6A,
15+
I32Sub = 0x6B,
1216
Call = 0x10,
1317
}

source/binary/types.d

+24
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,27 @@ struct Data
8484
///
8585
ubyte[] bytes;
8686
}
87+
88+
///
89+
struct Block
90+
{
91+
///
92+
BlockType blockType;
93+
}
94+
95+
///
96+
struct Void {}
97+
98+
alias BlockType = SumType!(
99+
Void,
100+
ValueType[],
101+
);
102+
103+
///
104+
size_t resultCount(BlockType blockType)
105+
{
106+
return blockType.match!(
107+
(Void _) => 0,
108+
(ValueType[] valueTypes) => valueTypes.length
109+
);
110+
}

0 commit comments

Comments
 (0)