summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Wirtz <dcode@dcode.io>2017-06-07 20:28:08 +0200
committerAlon Zakai <alonzakai@gmail.com>2017-06-07 11:28:08 -0700
commit2c220f5cebd915447e786f0b365b0bac1e2f719f (patch)
tree103ed218e637ff868e7ee067d51c25bdeb1a6f9a /src
parent3f0db5a7aafaaa4de713ff3ba3c3bbeb59fe566e (diff)
downloadbinaryen-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.cpp106
-rw-r--r--src/binaryen-c.h24
-rw-r--r--src/js/binaryen.js-post.js44
-rw-r--r--src/wasm-js.cpp4
-rw-r--r--src/wasm.h1
-rw-r--r--src/wasm/wasm.cpp11
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() {