diff options
author | Daniel Wirtz <dcode@dcode.io> | 2017-06-07 20:28:08 +0200 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2017-06-07 11:28:08 -0700 |
commit | 2c220f5cebd915447e786f0b365b0bac1e2f719f (patch) | |
tree | 103ed218e637ff868e7ee067d51c25bdeb1a6f9a /src | |
parent | 3f0db5a7aafaaa4de713ff3ba3c3bbeb59fe566e (diff) | |
download | binaryen-2c220f5cebd915447e786f0b365b0bac1e2f719f.tar.gz binaryen-2c220f5cebd915447e786f0b365b0bac1e2f719f.tar.bz2 binaryen-2c220f5cebd915447e786f0b365b0bac1e2f719f.zip |
Update binaryen-c/binaryen.js, fixes #1028, fixes #1029 (#1030)
This PR adds global variable support (addGlobal, getGlobal, setGlobal), host operations (currentMemory, growMemory), a few utility functions (removeImport, removeExport, getFunctionTypeBySignature with the latter being scheduled for removal once a better alternative is in place) and it introduces an additional argument to specify the result type in BinaryenBlock (effectively breaking the C-API but retaining previous behaviour by introducing the BinaryenUndefined() type for this purpose). Additionally, it enables compilation with exception support in build-js.sh as exceptions are thrown and caught when optimizing endless loops, intentionally resulting in an unreachable opcode. Affected test cases have been updated accordingly.
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 106 | ||||
-rw-r--r-- | src/binaryen-c.h | 24 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 44 | ||||
-rw-r--r-- | src/wasm-js.cpp | 4 | ||||
-rw-r--r-- | src/wasm.h | 1 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 11 |
6 files changed, 179 insertions, 11 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index d01c4329c..a824d77f7 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -94,6 +94,7 @@ BinaryenType BinaryenInt32(void) { return i32; } BinaryenType BinaryenInt64(void) { return i64; } BinaryenType BinaryenFloat32(void) { return f32; } BinaryenType BinaryenFloat64(void) { return f64; } +BinaryenType BinaryenUndefined(void) { return uint32_t(-1); } // Modules @@ -144,7 +145,7 @@ BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const if (tracing) { std::cout << " {\n"; - std::cout << " BinaryenIndex paramTypes[] = { "; + std::cout << " BinaryenType paramTypes[] = { "; for (BinaryenIndex i = 0; i < numParams; i++) { if (i > 0) std::cout << ", "; std::cout << paramTypes[i]; @@ -299,13 +300,14 @@ BinaryenOp BinaryenCurrentMemory(void) { return CurrentMemory; } BinaryenOp BinaryenGrowMemory(void) { return GrowMemory; } BinaryenOp BinaryenHasFeature(void) { return HasFeature; } -BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren) { +BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren, BinaryenType type) { auto* ret = ((Module*)module)->allocator.alloc<Block>(); if (name) ret->name = name; for (BinaryenIndex i = 0; i < numChildren; i++) { ret->list.push_back((Expression*)children[i]); } - ret->finalize(); + if (type != BinaryenUndefined()) ret->finalize(WasmType(type)); + else ret->finalize(); if (tracing) { std::cout << " {\n"; @@ -319,7 +321,10 @@ BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenBlock(the_module, "; traceNameOrNULL(name); - std::cout << ", children, " << numChildren << ");\n"; + std::cout << ", children, " << numChildren << ", "; + if (type == BinaryenUndefined()) std::cout << "BinaryenUndefined()"; + else std::cout << type; + std::cout << ");\n"; std::cout << " }\n"; } @@ -504,6 +509,32 @@ BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module, BinaryenIndex i ret->finalize(); return static_cast<Expression*>(ret); } +BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module, const char *name, BinaryenType type) { + auto* ret = ((Module*)module)->allocator.alloc<GetGlobal>(); + + if (tracing) { + auto id = noteExpression(ret); + std::cout << " expressions[" << id << "] = BinaryenGetGlobal(the_module, \"" << name << "\", " << type << ");\n"; + } + + ret->name = name; + ret->type = WasmType(type); + ret->finalize(); + return static_cast<Expression*>(ret); +} +BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module, const char *name, BinaryenExpressionRef value) { + auto* ret = ((Module*)module)->allocator.alloc<SetGlobal>(); + + if (tracing) { + auto id = noteExpression(ret); + std::cout << " expressions[" << id << "] = BinaryenSetGlobal(the_module, \"" << name << "\", expressions[" << expressions[value] << "]);\n"; + } + + ret->name = name; + ret->value = (Expression*)value; + ret->finalize(); + return static_cast<Expression*>(ret); +} BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int8_t signed_, uint32_t offset, uint32_t align, BinaryenType type, BinaryenExpressionRef ptr) { auto* ret = ((Module*)module)->allocator.alloc<Load>(); @@ -706,6 +737,21 @@ BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* na return ret; } +BinaryenImportRef BinaryenAddGlobal(BinaryenModuleRef module, const char* name, BinaryenType type, bool mutable_, BinaryenExpressionRef init) { + if (tracing) { + std::cout << " BinaryenAddGlobal(the_module, \"" << name << "\", types[" << type << "], " << mutable_ << ", " << expressions[init] << ");\n"; + } + + auto* wasm = (Module*)module; + auto* ret = new Global(); + ret->name = name; + ret->type = WasmType(type); + ret->mutable_ = mutable_; + ret->init = (Expression*)init; + wasm->addGlobal(ret); + return ret; +} + // Imports BinaryenImportRef BinaryenAddImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char *externalBaseName, BinaryenFunctionTypeRef type) { @@ -724,6 +770,15 @@ BinaryenImportRef BinaryenAddImport(BinaryenModuleRef module, const char* intern return ret; } +void BinaryenRemoveImport(BinaryenModuleRef module, const char* internalName) { + if (tracing) { + std::cout << " BinaryenRemoveImport(the_module, \"" << internalName << "\");\n"; + } + + auto* wasm = (Module*)module; + wasm->removeImport(internalName); +} + // Exports BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName) { @@ -739,6 +794,15 @@ BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* intern return ret; } +void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) { + if (tracing) { + std::cout << " BinaryenRemoveExport(the_module, \"" << externalName << "\");\n"; + } + + auto* wasm = (Module*)module; + wasm->removeExport(externalName); +} + // Function table. One per module void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenFunctionRef* funcs, BinaryenIndex numFuncs) { @@ -1030,4 +1094,38 @@ void BinaryenSetAPITracing(int on) { } } +// +// ========= Utilities ========= +// + +BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams) { + if (tracing) { + std::cout << " // BinaryenGetFunctionTypeBySignature\n"; + } + + auto* wasm = (Module*)module; + auto* test = new FunctionType; + test->result = WasmType(result); + for (BinaryenIndex i = 0; i < numParams; i++) { + test->params.push_back(WasmType(paramTypes[i])); + } + + // Lock. This can be called from multiple threads at once, and is a + // point where they all access and modify the module. + static std::mutex BinaryenAddFunctionTypeMutex; + { + std::lock_guard<std::mutex> lock(BinaryenAddFunctionTypeMutex); + for (BinaryenIndex i = 0; i < wasm->functionTypes.size(); i++) { + FunctionType* current = wasm->functionTypes[i].get(); + if (current->structuralComparison(*test)) { + delete test; + return current; + } + } + } + + delete test; + return NULL; +} + } // extern "C" diff --git a/src/binaryen-c.h b/src/binaryen-c.h index c7c1d7292..889b5ba45 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -72,6 +72,10 @@ BinaryenType BinaryenInt64(void); BinaryenType BinaryenFloat32(void); BinaryenType BinaryenFloat64(void); +// Not a real type. Used as the last parameter to BinaryenBlock to let +// the API figure out the type instead of providing one. +BinaryenType BinaryenUndefined(void); + // Modules // // Modules contain lists of functions, imports, exports, function types. The @@ -261,8 +265,11 @@ BinaryenOp BinaryenHasFeature(void); typedef void* BinaryenExpressionRef; -// Block: name can be NULL -BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren); +// Block: name can be NULL. Specifying BinaryenUndefined() as the 'type' +// parameter indicates that the block's type shall be figured out +// automatically instead of explicitly providing it. This conforms +// to the behavior before the 'type' parameter has been introduced. +BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren, BinaryenType type); // If: ifFalse can be NULL BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse); BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* in, BinaryenExpressionRef body); @@ -332,12 +339,14 @@ BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* na typedef void* BinaryenImportRef; BinaryenImportRef BinaryenAddImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char *externalBaseName, BinaryenFunctionTypeRef type); +void BinaryenRemoveImport(BinaryenModuleRef module, const char* internalName); // Exports typedef void* BinaryenExportRef; BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName); +void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName); // Function table. One per module @@ -432,6 +441,17 @@ BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper, RelooperBlo // TODO: compile-time option to enable/disable this feature entirely at build time? void BinaryenSetAPITracing(int on); +// +// ========= Utilities ========= +// + +// Note that this function has been added because there is no better alternative +// currently and is scheduled for removal once there is one. It takes the same set +// of parameters as BinaryenAddFunctionType but instead of adding a new function +// signature, it returns a pointer to the existing signature or NULL if there is no +// such signature yet. +BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index b5d8ab5b2..2f7defc63 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -27,6 +27,7 @@ Module['i64'] = Module['_BinaryenInt64'](); Module['f32'] = Module['_BinaryenFloat32'](); Module['f64'] = Module['_BinaryenFloat64'](); + Module['undefined'] = Module['_BinaryenUndefined'](); Module['ClzInt32'] = Module['_BinaryenClzInt32'](); Module['CtzInt32'] = Module['_BinaryenCtzInt32'](); @@ -170,11 +171,18 @@ i32sToStack(paramTypes), paramTypes.length); }); }; + this['getFunctionTypeBySignature'] = function(result, paramTypes) { + return preserveStack(function() { + return Module['_BinaryenGetFunctionTypeBySignature'](module, result, + i32sToStack(paramTypes), paramTypes.length); + }); + }; - this['block'] = function(name, children) { + this['block'] = function(name, children, type) { return preserveStack(function() { return Module['_BinaryenBlock'](module, name ? strToStack(name) : 0, - i32sToStack(children), children.length); + i32sToStack(children), children.length, + typeof type !== 'undefined' ? type : Module['undefined']); }); }; this['if'] = function(condition, ifTrue, ifFalse) { @@ -224,6 +232,21 @@ this['teeLocal'] = function(index, value) { return Module['_BinaryenTeeLocal'](module, index, value); }; + this['getGlobal'] = function(name, type) { + return Module['_BinaryenGetGlobal'](module, strToStack(name), type); + } + this['setGlobal'] = function(name, value) { + return Module['_BinaryenSetGlobal'](module, strToStack(name), value); + } + this['currentMemory'] = function() { + return Module['_BinaryenHost'](module, Module['CurrentMemory']); + } + this['growMemory'] = function(value) { + return Module['_BinaryenHost'](module, Module['GrowMemory'], null, i32sToStack([value]), 1); + } + this['hasFeature'] = function(name) { + return Module['_BinaryenHost'](module, Module['HasFeature'], strToStack(name)); + } // The Const creation API is a little different: we don't want users to // need to make their own Literals, as the C API handles them by value, @@ -745,16 +768,31 @@ return Module['_BinaryenAddFunction'](module, strToStack(name), functionType, i32sToStack(varTypes), varTypes.length, body); }); }; + this['addGlobal'] = function(name, type, mutable, init) { + return preserveStack(function() { + return Module['_BinaryenAddGlobal'](module, strToStack(name), type, mutable, init); + }); + } this['addImport'] = function(internalName, externalModuleName, externalBaseName, type) { return preserveStack(function() { return Module['_BinaryenAddImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), type); }); }; + this['removeImport'] = function(internalName) { + return preserveStack(function() { + return Module['_BinaryenRemoveImport'](module, strToStack(internalName)); + }); + }; this['addExport'] = function(internalName, externalName) { return preserveStack(function() { return Module['_BinaryenAddExport'](module, strToStack(internalName), strToStack(externalName)); }); }; + this['removeExport'] = function(externalName) { + return preserveStack(function() { + return Module['_BinaryenRemoveExport'](module, strToStack(externalName)); + }); + }; this['setFunctionTable'] = function(funcs) { return preserveStack(function() { return Module['_BinaryenSetFunctionTable'](module, i32sToStack(funcs), funcs.length); @@ -883,7 +921,7 @@ if (typeof exports != 'undefined') { (typeof window !== 'undefined' ? window : typeof global !== 'undefined' && ( typeof process === 'undefined' || - + // Note: We must export "Binaryen" even inside a CommonJS/AMD/UMD module // space because check.py generates a.js which requires Binaryen global var ( process.argv && diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp index dba194ee2..ec3f082bf 100644 --- a/src/wasm-js.cpp +++ b/src/wasm-js.cpp @@ -200,7 +200,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { var source = Module['HEAP8'].subarray($1, $1 + $2); var target = new Int8Array(Module['asmExports']['memory']); target.set(source, $0); - }, ConstantExpressionRunner(instance.globals).visit(segment.offset).value.geti32(), &segment.data[0], segment.data.size()); + }, ConstantExpressionRunner<TrivialGlobalManager>(instance.globals).visit(segment.offset).value.geti32(), &segment.data[0], segment.data.size()); } // look for imported table { @@ -228,7 +228,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { // Emulated table support is in a JS array. If the entry is a number, it's a function pointer. If not, it's a JS method to be called directly // TODO: make them all JS methods, wrapping a dynCall where necessary? for (auto segment : wasm.table.segments) { - Address offset = ConstantExpressionRunner(instance.globals).visit(segment.offset).value.geti32(); + Address offset = ConstantExpressionRunner<TrivialGlobalManager>(instance.globals).visit(segment.offset).value.geti32(); assert(offset + segment.data.size() <= wasm.table.initial); for (size_t i = 0; i != segment.data.size(); ++i) { Name name = segment.data[i]; diff --git a/src/wasm.h b/src/wasm.h index dba08d92e..f1f16a469 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -704,6 +704,7 @@ public: void addStart(const Name& s); void removeImport(Name name); + void removeExport(Name name); // TODO: remove* for other elements void updateMaps(); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index a879ebd05..201c8d183 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -663,6 +663,17 @@ void Module::removeImport(Name name) { } importsMap.erase(name); } + +void Module::removeExport(Name name) { + for (size_t i = 0; i < exports.size(); i++) { + if (exports[i]->name == name) { + exports.erase(exports.begin() + i); + break; + } + } + exportsMap.erase(name); +} + // TODO: remove* for other elements void Module::updateMaps() { |