Skip to content

Instantly share code, notes, and snippets.

@mirichi

mirichi/WebAssembly.rb Secret

Last active Mar 18, 2017
Embed
What would you like to do?
wasm出力テスト
def magic_number
"\0asm"
end
def version
"\x01\0\0\0"
end
# 固定長符号なし整数
def uint8(v);[v].pack("C");end
def uint16(v);[v].pack("v");end
def uint32(v);[v].pack("V");end
# LEB128の符号なし整数
def varuint(v)
b = v & 0x7f
if 0 <= v and v < 128
uint8(b)
else
uint8(b | 0x80) + varuint(v>>7)
end
end
# ビット数指定のLEB128符号なし整数
def varuint1(v);uint8(v & 0x01);end
def varuint7(v);uint8(v & 0x7f);end
def varuint32(v);varuint(v & 0xffffffff);end
# LEB128の符号あり整数
def varint(v)
b = v & 0x7f
if -64 <= v and v < 64
uint8(b)
else
uint8(b | 0x80) + varint(v>>7)
end
end
# よくわからない
def varint7(v);varint(v);end
def varint32(v);varint(v);end
def varint64(v);varint(v);end
# 型
LanguageTypes = {
:i32 => -1,
:i64 => -2,
:f32 => -3,
:f64 => -4,
:anyfunc => -16,
:func => -32,
:empty => -64,
}
# 定義の種類
ExternalKinds = {
:Function => 0,
:Table => 1,
:Memory => 2,
:Global => 3,
}
def value_type(vt)
varint7(LanguageTypes[vt])
end
# 関数シグネチャ
FuncType = Struct.new(:form, :param_types, :return_types)
def func_type(ft)
varint7(LanguageTypes[ft.form]) +
varuint32(ft.param_types.count) +
ft.param_types.map{|vt|value_type(vt)}.join +
varuint1(ft.return_types.count) +
ft.return_types.map{|vt|value_type(vt)}.join
end
# インポートエントリ
ImportEntry = Struct.new(:module_str, :field_str, :kind)
def import_entry(ie)
varuint32(ie.module_str.length) +
ie.module_str +
varuint32(ie.field_str.length) +
ie.field_str +
uint8(ExternalKinds[ie.kind])
end
# 関数
def functions(f)
varuint32(f.count) +
f.map{|type|varuint32(type)}.join
end
# エクスポートエントリ
ExportEntry = Struct.new(:field_str, :kind, :index)
def export_entry(ee)
varuint32(ee.field_str.length) +
ee.field_str +
uint8(ExternalKinds[ee.kind]) +
varuint32(ee.index)
end
# ファンクションボディ
FunctionBody = Struct.new(:locals, :code)
# ローカル変数情報
LocalEntry = Struct.new(:count, :type)
def local_entry(le)
varuint32(le.count) +
value_type(le.type)
end
def function_body(fb)
s = varuint32(fb.locals.count) +
fb.locals.map{|le|local_entry(le)}.join +
fb.code +
uint8(0x0b) #end
varuint32(s.length) + s
end
# WebAssemblyモジュールの情報をまとめたクラス
class WebAssembly
attr_accessor :func_types, :import_entries, :functions, :export_entries, :function_bodies
# セクションヘッダ編集
def section(id, s)
varuint7(id) +
varuint32(s.length) +
s
# カスタムセクションは未対応
end
# タイプセクション編集
def type_section
return "" if @func_types.count == 0
s = varuint32(@func_types.count) +
@func_types.map{|ft|func_type(ft)}.join
section(1, s)
end
# インポートセクション編集
def import_section
return "" if @import_entries.count == 0
s = varuint32(@import_entries.count) +
@import_entries.map{|ie|import_entry(ie)}.join
section(2, s)
end
# ファンクションセクション編集
def function_section
return "" if @functions.count == 0
s = varuint32(@functions.count) +
@functions.map{|type|varuint32(type)}.join
section(3, s)
end
# エクスポートセクション編集
def export_section
return "" if @export_entries.count == 0
s = varuint32(@export_entries.count) +
@export_entries.map{|ee|export_entry(ee)}.join
section(7, s)
end
# コードセクション編集
def code_section
return "" if @function_bodies.count == 0
s = varuint32(@function_bodies.count) +
@function_bodies.map{|fb|function_body(fb)}.join
section(10, s)
end
def write
open('D:\test\WebAssembly\test.wasm', "wb") do |fh|
fh.write magic_number
fh.write version
fh.write type_section
fh.write import_section
fh.write function_section
fh.write export_section
fh.write code_section
end
end
end
wa = WebAssembly.new
wa.func_types = [FuncType.new(:func, [:i32, :i32], [:i32])]
wa.import_entries = []
wa.functions = [0]
wa.export_entries = [ExportEntry.new("mul", :Function, 0)]
wa.function_bodies = [FunctionBody.new([], "\x20\x01\x20\x00\x6c")]
wa.write
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment