Skip to content

Commit 29da5c9

Browse files
COFFEETALEStlively
authored andcommitted
Ability to list each item on Exports/Data Segments/Functions (#2386)
Adds functionality to the C API for getting the number of items in a module and fetching them out by index.
1 parent 87d12c2 commit 29da5c9

8 files changed

+329
-1
lines changed

build-js.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ if [ "$1" == "-h" ] || [ "$1" == "--help" ] || [ "$1" == "-help" ]; then
1818
echo "usage: $0 [-g]" >&2
1919
echo " -g produce debug build" >&2
2020
echo ""
21-
echo "If EMSCRIPTEN is set in the envionment, emscripten will be loaded"
21+
echo "If EMSCRIPTEN is set in the environment, emscripten will be loaded"
2222
echo "from that directory. Otherwise the location of emscripten is resolved"
2323
echo "through PATH."
2424
exit 1
@@ -811,6 +811,12 @@ export_function "_BinaryenMemoryFillGetDest"
811811
export_function "_BinaryenMemoryFillGetValue"
812812
export_function "_BinaryenMemoryFillGetSize"
813813

814+
# 'Segments' query operations.
815+
export_function "_BinaryenGetNumMemorySegments"
816+
export_function "_BinaryenGetMemorySegmentByteOffset"
817+
export_function "_BinaryenGetMemorySegmentByteLength"
818+
export_function "_BinaryenCopyMemorySegmentData"
819+
814820
# 'Try' expression operations
815821
export_function "_BinaryenTryGetBody"
816822
export_function "_BinaryenTryGetCatchBody"
@@ -840,12 +846,16 @@ export_function "_BinaryenGetFunctionTypeBySignature"
840846
export_function "_BinaryenAddFunction"
841847
export_function "_BinaryenGetFunction"
842848
export_function "_BinaryenRemoveFunction"
849+
export_function "_BinaryenGetNumFunctions"
850+
export_function "_BinaryenGetFunctionByIndex"
843851
export_function "_BinaryenAddGlobal"
844852
export_function "_BinaryenGetGlobal"
845853
export_function "_BinaryenRemoveGlobal"
846854
export_function "_BinaryenAddEvent"
847855
export_function "_BinaryenGetEvent"
848856
export_function "_BinaryenRemoveEvent"
857+
export_function "_BinaryenGetNumExports"
858+
export_function "_BinaryenGetExportByIndex"
849859
export_function "_BinaryenAddFunctionImport"
850860
export_function "_BinaryenAddTableImport"
851861
export_function "_BinaryenAddMemoryImport"

src/binaryen-c.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3142,6 +3142,26 @@ void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name) {
31423142
auto* wasm = (Module*)module;
31433143
wasm->removeFunction(name);
31443144
}
3145+
uint32_t BinaryenGetNumFunctions(BinaryenModuleRef module) {
3146+
if (tracing) {
3147+
std::cout << " BinaryenGetNumFunctions(the_module);\n";
3148+
}
3149+
3150+
auto* wasm = (Module*)module;
3151+
return wasm->functions.size();
3152+
}
3153+
BinaryenFunctionRef BinaryenGetFunctionByIndex(BinaryenModuleRef module,
3154+
BinaryenIndex id) {
3155+
if (tracing) {
3156+
std::cout << " BinaryenGetFunctionByIndex(the_module, " << id << ");\n";
3157+
}
3158+
3159+
auto* wasm = (Module*)module;
3160+
if (wasm->functions.size() <= id) {
3161+
Fatal() << "invalid function id.";
3162+
}
3163+
return wasm->functions[id].get();
3164+
}
31453165

31463166
// Globals
31473167

@@ -3578,6 +3598,83 @@ void BinaryenSetMemory(BinaryenModuleRef module,
35783598
}
35793599
}
35803600

3601+
// Memory segments
3602+
3603+
uint32_t BinaryenGetNumMemorySegments(BinaryenModuleRef module) {
3604+
if (tracing) {
3605+
std::cout << " BinaryenGetNumMemorySegments(the_module);\n";
3606+
}
3607+
3608+
auto* wasm = (Module*)module;
3609+
return wasm->memory.segments.size();
3610+
}
3611+
int64_t BinaryenGetMemorySegmentByteOffset(BinaryenModuleRef module,
3612+
BinaryenIndex id) {
3613+
if (tracing) {
3614+
std::cout << " BinaryenGetMemorySegmentByteOffset(the_module, " << id
3615+
<< ");\n";
3616+
}
3617+
3618+
auto* wasm = (Module*)module;
3619+
if (wasm->memory.segments.size() <= id) {
3620+
Fatal() << "invalid segment id.";
3621+
}
3622+
3623+
auto globalOffset = [&](const Expression* const& expr,
3624+
int64_t& result) -> bool {
3625+
if (auto* c = expr->dynCast<Const>()) {
3626+
result = c->value.getInteger();
3627+
return true;
3628+
}
3629+
return false;
3630+
};
3631+
3632+
const Memory::Segment& segment = wasm->memory.segments[id];
3633+
3634+
int64_t ret;
3635+
if (globalOffset(segment.offset, ret)) {
3636+
return ret;
3637+
}
3638+
if (auto* get = segment.offset->dynCast<GlobalGet>()) {
3639+
Global* global = wasm->getGlobal(get->name);
3640+
if (globalOffset(global->init, ret)) {
3641+
return ret;
3642+
}
3643+
}
3644+
3645+
Fatal() << "non-constant offsets aren't supported yet";
3646+
return 0;
3647+
}
3648+
size_t BinaryenGetMemorySegmentByteLength(BinaryenModuleRef module,
3649+
BinaryenIndex id) {
3650+
if (tracing) {
3651+
std::cout << " BinaryenGetMemorySegmentByteLength(the_module, " << id
3652+
<< ");\n";
3653+
}
3654+
3655+
auto* wasm = (Module*)module;
3656+
if (wasm->memory.segments.size() <= id) {
3657+
Fatal() << "invalid segment id.";
3658+
}
3659+
const Memory::Segment& segment = wasm->memory.segments[id];
3660+
return segment.data.size();
3661+
}
3662+
void BinaryenCopyMemorySegmentData(BinaryenModuleRef module,
3663+
BinaryenIndex id,
3664+
char* buffer) {
3665+
if (tracing) {
3666+
std::cout << " BinaryenCopyMemorySegmentData(the_module, " << id << ", "
3667+
<< static_cast<void*>(buffer) << ");\n";
3668+
}
3669+
3670+
auto* wasm = (Module*)module;
3671+
if (wasm->memory.segments.size() <= id) {
3672+
Fatal() << "invalid segment id.";
3673+
}
3674+
const Memory::Segment& segment = wasm->memory.segments[id];
3675+
std::copy(segment.data.cbegin(), segment.data.cend(), buffer);
3676+
}
3677+
35813678
// Start function. One per module
35823679

35833680
void BinaryenSetStart(BinaryenModuleRef module, BinaryenFunctionRef start) {
@@ -4305,6 +4402,26 @@ const char* BinaryenExportGetValue(BinaryenExportRef export_) {
43054402

43064403
return ((Export*)export_)->value.c_str();
43074404
}
4405+
uint32_t BinaryenGetNumExports(BinaryenModuleRef module) {
4406+
if (tracing) {
4407+
std::cout << " BinaryenGetNumExports(the_module);\n";
4408+
}
4409+
4410+
auto* wasm = (Module*)module;
4411+
return wasm->exports.size();
4412+
}
4413+
BinaryenExportRef BinaryenGetExportByIndex(BinaryenModuleRef module,
4414+
BinaryenIndex id) {
4415+
if (tracing) {
4416+
std::cout << " BinaryenGetExportByIndex(the_module, " << id << ");\n";
4417+
}
4418+
4419+
auto* wasm = (Module*)module;
4420+
if (wasm->exports.size() <= id) {
4421+
Fatal() << "invalid export id.";
4422+
}
4423+
return wasm->exports[id].get();
4424+
}
43084425

43094426
//
43104427
// ========= Custom sections =========

src/binaryen-c.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,12 @@ BINARYEN_API BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
10641064
BINARYEN_API void BinaryenRemoveFunction(BinaryenModuleRef module,
10651065
const char* name);
10661066

1067+
// Gets the number of functions in the module.
1068+
BINARYEN_API uint32_t BinaryenGetNumFunctions(BinaryenModuleRef module);
1069+
// Get function pointer from its index.
1070+
BINARYEN_API BinaryenFunctionRef
1071+
BinaryenGetFunctionByIndex(BinaryenModuleRef module, BinaryenIndex id);
1072+
10671073
// Imports
10681074

10691075
BINARYEN_API void
@@ -1168,6 +1174,17 @@ BINARYEN_API void BinaryenSetMemory(BinaryenModuleRef module,
11681174
BinaryenIndex numSegments,
11691175
uint8_t shared);
11701176

1177+
// Memory segments. Query utilities.
1178+
1179+
BINARYEN_API uint32_t BinaryenGetNumMemorySegments(BinaryenModuleRef module);
1180+
BINARYEN_API int64_t
1181+
BinaryenGetMemorySegmentByteOffset(BinaryenModuleRef module, BinaryenIndex id);
1182+
BINARYEN_API size_t BinaryenGetMemorySegmentByteLength(BinaryenModuleRef module,
1183+
BinaryenIndex id);
1184+
BINARYEN_API void BinaryenCopyMemorySegmentData(BinaryenModuleRef module,
1185+
BinaryenIndex id,
1186+
char* buffer);
1187+
11711188
// Start function. One per module
11721189

11731190
BINARYEN_API void BinaryenSetStart(BinaryenModuleRef module,
@@ -1437,6 +1454,11 @@ BinaryenExportGetKind(BinaryenExportRef export_);
14371454
BINARYEN_API const char* BinaryenExportGetName(BinaryenExportRef export_);
14381455
// Gets the internal name of the specified export.
14391456
BINARYEN_API const char* BinaryenExportGetValue(BinaryenExportRef export_);
1457+
// Gets the number of exports in the module.
1458+
BINARYEN_API uint32_t BinaryenGetNumExports(BinaryenModuleRef module);
1459+
// Get export pointer from its index.
1460+
BINARYEN_API BinaryenExportRef
1461+
BinaryenGetExportByIndex(BinaryenModuleRef module, BinaryenIndex id);
14401462

14411463
//
14421464
// ========= Custom sections =========

src/js/binaryen.js-post.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,23 @@ function wrapModule(module, self) {
20962096
);
20972097
});
20982098
};
2099+
self['getNumMemorySegments'] = function() {
2100+
return Module['_BinaryenGetNumMemorySegments'](module);
2101+
}
2102+
self['getMemorySegmentInfoByIndex'] = function(id) {
2103+
return {
2104+
'byteOffset': Module['_BinaryenGetMemorySegmentByteOffset'](module, id),
2105+
'data': (function(){
2106+
var size = Module['_BinaryenGetMemorySegmentByteLength'](module, id);
2107+
var ptr = _malloc(size);
2108+
Module['_BinaryenCopyMemorySegmentData'](module, id, ptr);
2109+
var res = new Uint8Array(size);
2110+
res.set(new Uint8Array(buffer, ptr, size));
2111+
_free(ptr);
2112+
return res.buffer;
2113+
})()
2114+
};
2115+
}
20992116
self['setStart'] = function(start) {
21002117
return Module['_BinaryenSetStart'](module, start);
21012118
};
@@ -2110,6 +2127,18 @@ function wrapModule(module, self) {
21102127
return Module['_BinaryenAddCustomSection'](module, strToStack(name), i8sToStack(contents), contents.length);
21112128
});
21122129
};
2130+
self['getNumExports'] = function() {
2131+
return Module['_BinaryenGetNumExports'](module);
2132+
}
2133+
self['getExportByIndex'] = function(id) {
2134+
return Module['_BinaryenGetExportByIndex'](module, id);
2135+
}
2136+
self['getNumFunctions'] = function() {
2137+
return Module['_BinaryenGetNumFunctions'](module);
2138+
}
2139+
self['getFunctionByIndex'] = function(id) {
2140+
return Module['_BinaryenGetFunctionByIndex'](module, id);
2141+
}
21132142
self['emitText'] = function() {
21142143
var old = out;
21152144
var ret = '';

test/binaryen.js/kitchen-sink.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,60 @@ function test_internals() {
887887
console.log('sizeof Literal: ' + Binaryen['_BinaryenSizeofLiteral']());
888888
}
889889

890+
function test_for_each() {
891+
module = new Binaryen.Module();
892+
893+
var v = module.addFunctionType("v", Binaryen.None, []);
894+
895+
var fns = [
896+
module.addFunction("fn0", v, [], module.nop()),
897+
module.addFunction("fn1", v, [], module.nop()),
898+
module.addFunction("fn2", v, [], module.nop())
899+
];
900+
901+
var i;
902+
for (i = 0 ; i < module.getNumFunctions() ; i++) {
903+
assert(module.getFunctionByIndex(i) === fns[i]);
904+
}
905+
906+
var exps = [
907+
module.addFunctionExport("fn0", "export0"),
908+
module.addFunctionExport("fn1", "export1"),
909+
module.addFunctionExport("fn2", "export2")
910+
];
911+
912+
for (i = 0 ; i < module.getNumExports() ; i++) {
913+
assert(module.getExportByIndex(i) === exps[i]);
914+
}
915+
916+
var expected_offsets = [10, 125];
917+
var expected_data = ["hello, world", "segment data 2"];
918+
919+
var global = module.addGlobal("a-global", Binaryen.i32, false, module.i32.const(expected_offsets[1]))
920+
module.setMemory(1, 256, "mem", [
921+
{
922+
passive: false,
923+
offset: module.i32.const(expected_offsets[0]),
924+
data: expected_data[0].split('').map(function(x) { return x.charCodeAt(0) })
925+
},
926+
{
927+
passive: false,
928+
offset: module.global.get("a-global"),
929+
data: expected_data[1].split('').map(function(x) { return x.charCodeAt(0) })
930+
}
931+
], false);
932+
for (i = 0 ; i < module.getNumMemorySegments() ; i++) {
933+
var segment = module.getMemorySegmentInfoByIndex(i);
934+
assert(expected_offsets[i] === segment.byteOffset);
935+
var data8 = new Uint8Array(segment.data);
936+
var str = String.fromCharCode.apply(null, data8);
937+
assert(expected_data[i] === str);
938+
}
939+
940+
console.log(module.emitText());
941+
module.dispose();
942+
}
943+
890944
function main() {
891945
test_types();
892946
test_features();
@@ -899,6 +953,7 @@ function main() {
899953
test_tracing();
900954
test_parsing();
901955
test_internals();
956+
test_for_each();
902957
}
903958

904959
main();

test/binaryen.js/kitchen-sink.js.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9699,3 +9699,23 @@ module loaded from text form:
96999699
)
97009700

97019701
sizeof Literal: 24
9702+
(module
9703+
(type $v (func))
9704+
(memory $0 1 256)
9705+
(data (i32.const 10) "hello, world")
9706+
(data (global.get $a-global) "segment data 2")
9707+
(global $a-global i32 (i32.const 125))
9708+
(export "export0" (func $fn0))
9709+
(export "export1" (func $fn1))
9710+
(export "export2" (func $fn2))
9711+
(export "mem" (memory $0))
9712+
(func $fn0 (; 0 ;) (type $v)
9713+
(nop)
9714+
)
9715+
(func $fn1 (; 1 ;) (type $v)
9716+
(nop)
9717+
)
9718+
(func $fn2 (; 2 ;) (type $v)
9719+
(nop)
9720+
)
9721+
)

0 commit comments

Comments
 (0)