summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp17
-rw-r--r--src/binaryen-c.h1
-rw-r--r--src/ir/block-utils.h2
-rw-r--r--src/ir/features.h8
-rw-r--r--src/ir/global-utils.h2
-rw-r--r--src/js/binaryen.js-post.js95
-rw-r--r--src/parsing.h4
-rw-r--r--src/passes/CoalesceLocals.cpp2
-rw-r--r--src/passes/Metrics.cpp3
-rw-r--r--src/passes/Strip.cpp19
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--src/passes/passes.h1
-rw-r--r--src/support/colors.h2
-rw-r--r--src/support/file.cpp12
-rw-r--r--src/support/file.h2
-rw-r--r--src/tools/spec-wrapper.h2
-rw-r--r--src/tools/tool-options.h10
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp13
-rw-r--r--src/wasm-binary.h1
-rw-r--r--src/wasm-emscripten.h8
-rw-r--r--src/wasm-features.h70
-rw-r--r--src/wasm-io.h6
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm-type.h3
-rw-r--r--src/wasm.h57
-rw-r--r--src/wasm/literal.cpp2
-rw-r--r--src/wasm/wasm-emscripten.cpp137
-rw-r--r--src/wasm/wasm-io.cpp46
-rw-r--r--src/wasm/wasm-s-parser.cpp56
-rw-r--r--src/wasm/wasm-type.cpp8
-rw-r--r--src/wasm/wasm-validator.cpp5
-rw-r--r--src/wasm/wasm.cpp1
32 files changed, 330 insertions, 267 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index c554b0a23..71cd92da4 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1616,6 +1616,15 @@ double BinaryenConstGetValueF64(BinaryenExpressionRef expr) {
assert(expression->is<Const>());
return static_cast<Const*>(expression)->value.getf64();
}
+void BinaryenConstGetValueV128(BinaryenExpressionRef expr, uint8_t* out) {
+ if (tracing) {
+ std::cout << " BinaryenConstGetValueV128(expressions[" << expressions[expr] << "], " << out << ");\n";
+ }
+
+ auto* expression = (Expression*)expr;
+ assert(expression->is<Const>());
+ memcpy(out, static_cast<Const*>(expression)->value.getv128().data(), 16);
+}
// Unary
BinaryenOp BinaryenUnaryGetOp(BinaryenExpressionRef expr) {
if (tracing) {
@@ -1945,7 +1954,7 @@ BinaryenExpressionRef BinaryenSIMDShuffleGetRight(BinaryenExpressionRef expr) {
}
void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t *mask) {
if (tracing) {
- std::cout << " BinaryenSIMDShuffleGetMask(expressions[" << expressions[expr] << "]);\n";
+ std::cout << " BinaryenSIMDShuffleGetMask(expressions[" << expressions[expr] << "], " << mask << ");\n";
}
auto* expression = (Expression*)expr;
@@ -3067,6 +3076,12 @@ size_t BinaryenSizeofLiteral(void) {
return sizeof(Literal);
}
+// Returns the size of an allocate and write result object.
+EMSCRIPTEN_KEEPALIVE
+size_t BinaryenSizeofAllocateAndWriteResult(void) {
+ return sizeof(BinaryenModuleAllocateAndWriteResult);
+}
+
#endif
} // extern "C"
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 5355ceeeb..787bfb242 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -618,6 +618,7 @@ int32_t BinaryenConstGetValueI64Low(BinaryenExpressionRef expr);
int32_t BinaryenConstGetValueI64High(BinaryenExpressionRef expr);
float BinaryenConstGetValueF32(BinaryenExpressionRef expr);
double BinaryenConstGetValueF64(BinaryenExpressionRef expr);
+void BinaryenConstGetValueV128(BinaryenExpressionRef expr, uint8_t* out);
BinaryenOp BinaryenUnaryGetOp(BinaryenExpressionRef expr);
BinaryenExpressionRef BinaryenUnaryGetValue(BinaryenExpressionRef expr);
diff --git a/src/ir/block-utils.h b/src/ir/block-utils.h
index e3ad370db..968332212 100644
--- a/src/ir/block-utils.h
+++ b/src/ir/block-utils.h
@@ -59,7 +59,7 @@ namespace BlockUtils {
inline Expression* simplifyToContentsWithPossibleTypeChange(Block* block, T* parent) {
return simplifyToContents(block, parent, true);
}
-};
+}
} // namespace wasm
diff --git a/src/ir/features.h b/src/ir/features.h
index ed7fb6ff5..505e239a5 100644
--- a/src/ir/features.h
+++ b/src/ir/features.h
@@ -76,6 +76,14 @@ inline FeatureSet get(UnaryOp op) {
ret.setSIMD();
break;
}
+ case ExtendS8Int32:
+ case ExtendS16Int32:
+ case ExtendS8Int64:
+ case ExtendS16Int64:
+ case ExtendS32Int64: {
+ ret.setSignExt();
+ break;
+ }
default: {}
}
return ret;
diff --git a/src/ir/global-utils.h b/src/ir/global-utils.h
index 02bbbf2d2..fa4cdc44a 100644
--- a/src/ir/global-utils.h
+++ b/src/ir/global-utils.h
@@ -48,7 +48,7 @@ namespace GlobalUtils {
});
return ret;
}
-};
+}
} // namespace wasm
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index 1eef5757e..aee41255c 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -365,6 +365,13 @@ Module['ConvertUVecI32x4ToVecF32x4'] = Module['_BinaryenConvertUVecI32x4ToVecF32
Module['ConvertSVecI64x2ToVecF64x2'] = Module['_BinaryenConvertSVecI64x2ToVecF64x2']();
Module['ConvertUVecI64x2ToVecF64x2'] = Module['_BinaryenConvertUVecI64x2ToVecF64x2']();
+// The size of a single literal in memory as used in Const creation,
+// which is a little different: we don't want users to need to make
+// their own Literals, as the C API handles them by value, which means
+// we would leak them. Instead, Const creation is fused together with
+// an intermediate stack allocation of this size to pass the value.
+var sizeOfLiteral = _BinaryenSizeofLiteral();
+
// 'Module' interface
Module['Module'] = function(module) {
assert(!module); // guard against incorrect old API usage
@@ -482,13 +489,6 @@ function wrapModule(module, self) {
}
}
- // 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,
- // which means we would leak them. Instead, this is the only API that
- // accepts Literals, so fuse it with Literal creation
- var temp = _malloc(Module['_BinaryenSizeofLiteral']()); // a single literal in memory. the LLVM C ABI
- // makes us pass pointers to this.
-
self['i32'] = {
'load': function(offset, align, ptr) {
return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i32'], ptr);
@@ -515,8 +515,11 @@ function wrapModule(module, self) {
return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i32']);
},
'const': function(x) {
- Module['_BinaryenLiteralInt32'](temp, x);
- return Module['_BinaryenConst'](module, temp);
+ return preserveStack(function() {
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralInt32'](tempLiteral, x);
+ return Module['_BinaryenConst'](module, tempLiteral);
+ });
},
'clz': function(value) {
return Module['_BinaryenUnary'](module, Module['ClzInt32'], value);
@@ -778,8 +781,11 @@ function wrapModule(module, self) {
return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64']);
},
'const': function(x, y) {
- Module['_BinaryenLiteralInt64'](temp, x, y);
- return Module['_BinaryenConst'](module, temp);
+ return preserveStack(function() {
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralInt64'](tempLiteral, x, y);
+ return Module['_BinaryenConst'](module, tempLiteral);
+ });
},
'clz': function(value) {
return Module['_BinaryenUnary'](module, Module['ClzInt64'], value);
@@ -1049,12 +1055,18 @@ function wrapModule(module, self) {
return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['f32']);
},
'const': function(x) {
- Module['_BinaryenLiteralFloat32'](temp, x);
- return Module['_BinaryenConst'](module, temp);
+ return preserveStack(function() {
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralFloat32'](tempLiteral, x);
+ return Module['_BinaryenConst'](module, tempLiteral);
+ });
},
'const_bits': function(x) {
- Module['_BinaryenLiteralFloat32Bits'](temp, x);
- return Module['_BinaryenConst'](module, temp);
+ return preserveStack(function() {
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralFloat32Bits'](tempLiteral, x);
+ return Module['_BinaryenConst'](module, tempLiteral);
+ });
},
'neg': function(value) {
return Module['_BinaryenUnary'](module, Module['NegFloat32'], value);
@@ -1148,12 +1160,18 @@ function wrapModule(module, self) {
return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['f64']);
},
'const': function(x) {
- Module['_BinaryenLiteralFloat64'](temp, x);
- return Module['_BinaryenConst'](module, temp);
+ return preserveStack(function() {
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralFloat64'](tempLiteral, x);
+ return Module['_BinaryenConst'](module, tempLiteral);
+ });
},
'const_bits': function(x, y) {
- Module['_BinaryenLiteralFloat64Bits'](temp, x, y);
- return Module['_BinaryenConst'](module, temp);
+ return preserveStack(function() {
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralFloat64Bits'](tempLiteral, x, y);
+ return Module['_BinaryenConst'](module, tempLiteral);
+ });
},
'neg': function(value) {
return Module['_BinaryenUnary'](module, Module['NegFloat64'], value);
@@ -1248,8 +1266,9 @@ function wrapModule(module, self) {
},
'const': function(i8s) {
return preserveStack(function() {
- Module['_BinaryenLiteralVec128'](temp, i8sToStack(i8s));
- return Module['_BinaryenConst'](module, temp);
+ var tempLiteral = stackAlloc(sizeOfLiteral);
+ Module['_BinaryenLiteralVec128'](tempLiteral, i8sToStack(i8s));
+ return Module['_BinaryenConst'](module, tempLiteral);
});
},
'not': function(value) {
@@ -1729,7 +1748,7 @@ function wrapModule(module, self) {
});
};
self['removeFunctionType'] = function(name) {
- return preserveStack(function () {
+ return preserveStack(function() {
return Module['_BinaryenRemoveFunctionType'](module, strToStack(name));
});
};
@@ -1754,7 +1773,7 @@ function wrapModule(module, self) {
});
}
self['removeGlobal'] = function(name) {
- return preserveStack(function () {
+ return preserveStack(function() {
return Module['_BinaryenRemoveGlobal'](module, strToStack(name));
});
}
@@ -1900,10 +1919,11 @@ function wrapModule(module, self) {
};
self['emitBinary'] = function(sourceMapUrl) {
return preserveStack(function() {
- Module['_BinaryenModuleAllocateAndWrite'](temp, module, strToStack(sourceMapUrl));
- var binaryPtr = HEAPU32[ temp >>> 2 ];
- var binaryBytes = HEAPU32[(temp >>> 2) + 1];
- var sourceMapPtr = HEAPU32[(temp >>> 2) + 2];
+ var tempBuffer = stackAlloc(_BinaryenSizeofAllocateAndWriteResult());
+ Module['_BinaryenModuleAllocateAndWrite'](tempBuffer, module, strToStack(sourceMapUrl));
+ var binaryPtr = HEAPU32[ tempBuffer >>> 2 ];
+ var binaryBytes = HEAPU32[(tempBuffer >>> 2) + 1];
+ var sourceMapPtr = HEAPU32[(tempBuffer >>> 2) + 2];
try {
var buffer = new Uint8Array(binaryBytes);
buffer.set(HEAPU8.subarray(binaryPtr, binaryPtr + binaryBytes));
@@ -2090,7 +2110,18 @@ Module['getExpressionInfo'] = function(expr) {
case Module['i32']: value = Module['_BinaryenConstGetValueI32'](expr); break;
case Module['i64']: value = { 'low': Module['_BinaryenConstGetValueI64Low'](expr), 'high': Module['_BinaryenConstGetValueI64High'](expr) }; break;
case Module['f32']: value = Module['_BinaryenConstGetValueF32'](expr); break;
- case Module['f64']: value = Module['_BinaryenConstGetValueF64'](expr); break;
+ case Module['f64']: value = Module['_BinaryenConstGetValueF64'](expr); break;
+ case Module['v128']: {
+ preserveStack(function() {
+ var tempBuffer = stackAlloc(16);
+ Module['_BinaryenConstGetValueV128'](expr, tempBuffer);
+ value = new Array(16);
+ for (var i = 0 ; i < 16; i++) {
+ value[i] = HEAPU8[tempBuffer + i];
+ }
+ });
+ break;
+ }
default: throw Error('unexpected type: ' + type);
}
return {
@@ -2203,11 +2234,11 @@ Module['getExpressionInfo'] = function(expr) {
};
case Module['SIMDShuffleId']:
return preserveStack(function() {
- var ret = stackAlloc(16);
- Module['_BinaryenSIMDShuffleGetMask'](expr, ret);
- var mask = [];
+ var tempBuffer = stackAlloc(16);
+ Module['_BinaryenSIMDShuffleGetMask'](expr, tempBuffer);
+ var mask = new Array(16);
for (var i = 0 ; i < 16; i++) {
- mask[i] = HEAP8[ret + i];
+ mask[i] = HEAPU8[tempBuffer + i];
}
return {
'id': id,
diff --git a/src/parsing.h b/src/parsing.h
index 6eecb38f2..97fc88432 100644
--- a/src/parsing.h
+++ b/src/parsing.h
@@ -40,7 +40,7 @@ struct ParseException {
ParseException(std::string text) : text(text), line(-1), col(-1) {}
ParseException(std::string text, size_t line, size_t col) : text(text), line(line), col(col) {}
- void dump(std::ostream& o) {
+ void dump(std::ostream& o) const {
Colors::magenta(o);
o << "[";
Colors::red(o);
@@ -63,7 +63,7 @@ struct MapParseException {
MapParseException() : text("unknown parse error") {}
MapParseException(std::string text) : text(text) {}
- void dump(std::ostream& o) {
+ void dump(std::ostream& o) const {
Colors::magenta(o);
o << "[";
Colors::red(o);
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index 2835744d3..621383ca4 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -275,7 +275,7 @@ std::vector<Index> adjustOrderByPriorities(std::vector<Index>& baseline, std::ve
return priorities[x] > priorities[y] || (priorities[x] == priorities[y] && reversed[x] < reversed[y]);
});
return ret;
-};
+}
void CoalesceLocals::pickIndices(std::vector<Index>& indices) {
if (numLocals == 0) return;
diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp
index b794ea32d..8717a86b7 100644
--- a/src/passes/Metrics.cpp
+++ b/src/passes/Metrics.cpp
@@ -66,6 +66,7 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
counts["[imports]"] = imports.getNumImports();
// add functions
counts["[funcs]"] = imports.getNumDefinedFunctions();
+ counts["[exports]"] = module->exports.size();
// add memory and table
if (module->memory.exists) {
Index size = 0;
@@ -172,7 +173,7 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
o << title << "\n";
for (auto* key : keys) {
auto value = counts[key];
- if (value == 0) continue;
+ if (value == 0 && key[0] != '[') continue;
o << " " << left << setw(15) << key << ": " << setw(8)
<< value;
if (lastCounts.count(key)) {
diff --git a/src/passes/Strip.cpp b/src/passes/Strip.cpp
index 8ab712cb1..40e5a9e9d 100644
--- a/src/passes/Strip.cpp
+++ b/src/passes/Strip.cpp
@@ -47,11 +47,15 @@ struct Strip : public Pass {
),
sections.end()
);
- // Clean up internal data structures.
- module->clearDebugInfo();
- for (auto& func : module->functions) {
- func->clearNames();
- func->clearDebugInfo();
+ // If we're cleaning up debug info, clear on the function and module too.
+ UserSection temp;
+ temp.name = BinaryConsts::UserSections::Name;
+ if (decider(temp)) {
+ module->clearDebugInfo();
+ for (auto& func : module->functions) {
+ func->clearNames();
+ func->clearDebugInfo();
+ }
}
}
};
@@ -71,4 +75,9 @@ Pass *createStripProducersPass() {
});
}
+Pass *createStripTargetFeaturesPass() {
+ return new Strip([&](const UserSection& curr) {
+ return curr.name == BinaryConsts::UserSections::TargetFeatures;
+ });
+}
} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 3712bf19e..5d8b8d2c8 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -138,6 +138,7 @@ void PassRegistry::registerPasses() {
registerPass("strip", "deprecated; same as strip-debug", createStripDebugPass);
registerPass("strip-debug", "strip debug info (including the names section)", createStripDebugPass);
registerPass("strip-producers", "strip the wasm producers section", createStripProducersPass);
+ registerPass("strip-target-features", "strip the wasm target features section", createStripTargetFeaturesPass);
registerPass("trap-mode-clamp", "replace trapping operations with clamping semantics", createTrapModeClamp);
registerPass("trap-mode-js", "replace trapping operations with js semantics", createTrapModeJS);
registerPass("untee", "removes local.tees, replacing them with sets and gets", createUnteePass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index ab11721fb..ac7126bd4 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -88,6 +88,7 @@ Pass* createSimplifyLocalsNoStructurePass();
Pass* createSimplifyLocalsNoTeeNoStructurePass();
Pass* createStripDebugPass();
Pass* createStripProducersPass();
+Pass* createStripTargetFeaturesPass();
Pass* createSouperifyPass();
Pass* createSouperifySingleUsePass();
Pass* createSpillPointersPass();
diff --git a/src/support/colors.h b/src/support/colors.h
index fb5267ce1..6761639d9 100644
--- a/src/support/colors.h
+++ b/src/support/colors.h
@@ -52,6 +52,6 @@ inline void green(std::ostream& stream) {}
inline void blue(std::ostream& stream) {}
inline void bold(std::ostream& stream) {}
#endif
-};
+}
#endif // wasm_support_color_h
diff --git a/src/support/file.cpp b/src/support/file.cpp
index 19401b21d..2fe636cfd 100644
--- a/src/support/file.cpp
+++ b/src/support/file.cpp
@@ -21,6 +21,17 @@
#include <cstdint>
#include <limits>
+std::vector<char> wasm::read_stdin(Flags::DebugOption debug) {
+ if (debug == Flags::Debug) std::cerr << "Loading stdin..." << std::endl;
+ std::vector<char> input;
+ char c;
+ while (std::cin.get(c) && !std::cin.eof()) {
+ input.push_back(c);
+ }
+ return input;
+}
+
+
template<typename T>
T wasm::read_file(const std::string& filename, Flags::BinaryOption binary, Flags::DebugOption debug) {
if (debug == Flags::Debug) std::cerr << "Loading '" << filename << "'..." << std::endl;
@@ -84,4 +95,3 @@ size_t wasm::file_size(std::string filename) {
std::ifstream infile(filename, std::ifstream::ate | std::ifstream::binary);
return infile.tellg();
}
-
diff --git a/src/support/file.h b/src/support/file.h
index e94d23fad..cb9c82ca9 100644
--- a/src/support/file.h
+++ b/src/support/file.h
@@ -39,6 +39,8 @@ namespace Flags {
};
}
+std::vector<char> read_stdin(Flags::DebugOption);
+
template<typename T>
T read_file(const std::string& filename, Flags::BinaryOption binary, Flags::DebugOption debug);
// Declare the valid explicit specializations.
diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h
index a42230fc1..77db8a0f4 100644
--- a/src/tools/spec-wrapper.h
+++ b/src/tools/spec-wrapper.h
@@ -34,7 +34,7 @@ static std::string generateSpecWrapper(Module& wasm) {
case i64: ret += "(i64.const 0)"; break;
case f32: ret += "(f32.const 0)"; break;
case f64: ret += "(f64.const 0)"; break;
- case v128: ret += "(v128.const i32 0 0 0 0)"; break;
+ case v128: ret += "(v128.const i32x4 0 0 0 0)"; break;
case none:
case unreachable: WASM_UNREACHABLE();
}
diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h
index 5620883ec..671085a4e 100644
--- a/src/tools/tool-options.h
+++ b/src/tools/tool-options.h
@@ -39,6 +39,16 @@ struct ToolOptions : public Options {
[this](Options *o, const std::string& arguments) {
passOptions.features = FeatureSet::All;
})
+ .add("--enable-sign-ext", "", "Enable sign extension operations",
+ Options::Arguments::Zero,
+ [this](Options *o, const std::string& arguments) {
+ passOptions.features.setSignExt();
+ })
+ .add("--disable-sign-ext", "", "Disable sign extension operations",
+ Options::Arguments::Zero,
+ [this](Options *o, const std::string& arguments) {
+ passOptions.features.setSignExt(false);
+ })
.add("--enable-threads", "", "Enable atomic operations",
Options::Arguments::Zero,
[this](Options *o, const std::string& arguments) {
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index 42fc1e4db..2aa5de46f 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -47,7 +47,6 @@ int main(int argc, const char *argv[]) {
bool emitBinary = true;
bool debugInfo = false;
bool legalizeJavaScriptFFI = true;
- unsigned numReservedFunctionPointers = 0;
uint64_t globalBase = INVALID_BASE;
uint64_t initialStackPointer = INVALID_BASE;
Options options("wasm-emscripten-finalize",
@@ -70,14 +69,6 @@ int main(int argc, const char *argv[]) {
[&emitBinary](Options*, const std::string& ) {
emitBinary = false;
})
- .add("--emscripten-reserved-function-pointers", "",
- "Number of reserved function pointers for emscripten addFunction "
- "support",
- Options::Arguments::One,
- [&numReservedFunctionPointers](Options *,
- const std::string &argument) {
- numReservedFunctionPointers = std::stoi(argument);
- })
.add("--global-base", "", "The address at which static globals were placed",
Options::Arguments::One,
[&globalBase](Options*, const std::string&argument ) {
@@ -203,7 +194,6 @@ int main(int argc, const char *argv[]) {
}
generator.generateDynCallThunks();
- generator.generateJSCallThunks(numReservedFunctionPointers);
// Legalize the wasm.
{
@@ -214,11 +204,12 @@ int main(int argc, const char *argv[]) {
legalizeJavaScriptFFI ? ABI::LegalizationLevel::Full
: ABI::LegalizationLevel::Minimal
));
+ passRunner.add("strip-target-features");
passRunner.run();
}
// Substantial changes to the wasm are done, enough to create the metadata.
- std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions, numReservedFunctionPointers);
+ std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions);
// Finally, separate out data segments if relevant (they may have been needed
// for metadata).
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index a875db791..32166af00 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -345,6 +345,7 @@ extern const char* SourceMapUrl;
extern const char* Dylink;
extern const char* Linking;
extern const char* Producers;
+extern const char* TargetFeatures;
enum Subsection {
NameFunction = 1,
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index 275c809fd..acb2994ad 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -46,14 +46,8 @@ public:
// and restore functions.
void replaceStackPointerGlobal();
- // Create thunks to support emscripten's addFunction functionality. Creates (#
- // of reserved function pointers) thunks for each indirectly called function
- // signature.
- void generateJSCallThunks(unsigned numReservedFunctionPointers);
-
std::string generateEmscriptenMetadata(
- Address staticBump, std::vector<Name> const& initializerFunctions,
- unsigned numReservedFunctionPointers);
+ Address staticBump, std::vector<Name> const& initializerFunctions);
void fixInvokeFunctionNames();
diff --git a/src/wasm-features.h b/src/wasm-features.h
new file mode 100644
index 000000000..4dd806e28
--- /dev/null
+++ b/src/wasm-features.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_features_h
+#define wasm_features_h
+
+#include <stdint.h>
+
+struct FeatureSet {
+ enum Feature : uint32_t {
+ MVP = 0,
+ Atomics = 1 << 0,
+ MutableGlobals = 1 << 1,
+ TruncSat = 1 << 2,
+ SIMD = 1 << 3,
+ BulkMemory = 1 << 4,
+ SignExt = 1 << 5,
+ All = Atomics | MutableGlobals | TruncSat | SIMD | BulkMemory | SignExt
+ };
+
+ FeatureSet() : features(MVP) {}
+ FeatureSet(uint32_t features) : features(features) {}
+
+ bool isMVP() const { return features == MVP; }
+ bool has(Feature f) { return (features & f) == f; }
+ bool hasAtomics() const { return features & Atomics; }
+ bool hasMutableGlobals() const { return features & MutableGlobals; }
+ bool hasTruncSat() const { return features & TruncSat; }
+ bool hasSIMD() const { return features & SIMD; }
+ bool hasBulkMemory() const { return features & BulkMemory; }
+ bool hasSignExt() const { return features & SignExt; }
+ bool hasAll() const { return features & All; }
+
+ void makeMVP() { features = MVP; }
+ void set(Feature f, bool v = true) { features = v ? (features | f) : (features & ~f); }
+ void setAtomics(bool v = true) { set(Atomics, v); }
+ void setMutableGlobals(bool v = true) { set(MutableGlobals, v); }
+ void setTruncSat(bool v = true) { set(TruncSat, v); }
+ void setSIMD(bool v = true) { set(SIMD, v); }
+ void setBulkMemory(bool v = true) { set(BulkMemory, v); }
+ void setSignExt(bool v = true) { set(SignExt, v); }
+ void setAll(bool v = true) { features = v ? All : MVP; }
+
+ bool operator<=(const FeatureSet& other) {
+ return !(features & ~other.features);
+ }
+
+ FeatureSet& operator|=(const FeatureSet& other) {
+ features |= other.features;
+ return *this;
+ }
+
+private:
+ uint32_t features;
+};
+
+#endif // wasm_features_h
diff --git a/src/wasm-io.h b/src/wasm-io.h
index 2dfdbae6c..6d8dcc6e5 100644
--- a/src/wasm-io.h
+++ b/src/wasm-io.h
@@ -42,11 +42,15 @@ public:
// read binary
void readBinary(std::string filename, Module& wasm,
std::string sourceMapFilename="");
- // read text or binary, checking the contents for what it is
+ // read text or binary, checking the contents for what it is. If `filename` is
+ // empty, read from stdin.
void read(std::string filename, Module& wasm,
std::string sourceMapFilename="");
// check whether a file is a wasm binary
bool isBinaryFile(std::string filename);
+
+private:
+ void readStdin(Module& wasm, std::string sourceMapFilename);
};
class ModuleWriter : public ModuleIO {
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index f0ed79409..07de235a2 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -152,6 +152,7 @@ private:
return stringToType(str.str, allowError, prefix);
}
Type stringToType(const char* str, bool allowError=false, bool prefix=false);
+ Type stringToLaneType(const char* str);
bool isType(cashew::IString str) {
return stringToType(str, true) != none;
}
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 0b99fa53a..60253f6ab 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -17,6 +17,8 @@
#ifndef wasm_wasm_type_h
#define wasm_wasm_type_h
+#include "wasm-features.h"
+
namespace wasm {
enum Type {
@@ -33,6 +35,7 @@ enum Type {
const char* printType(Type type);
unsigned getTypeSize(Type type);
+FeatureSet getFeatures(Type type);
Type getType(unsigned size, bool float_);
Type getReachableType(Type a, Type b);
bool isConcreteType(Type type);
diff --git a/src/wasm.h b/src/wasm.h
index a16dab478..ab9d7c816 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -35,49 +35,10 @@
#include "mixed_arena.h"
#include "support/name.h"
#include "wasm-type.h"
+#include "wasm-features.h"
namespace wasm {
-struct FeatureSet {
- enum Feature : uint32_t {
- MVP = 0,
- Atomics = 1 << 0,
- MutableGlobals = 1 << 1,
- TruncSat = 1 << 2,
- SIMD = 1 << 3,
- BulkMemory = 1 << 4,
- All = Atomics | MutableGlobals | TruncSat | SIMD | BulkMemory
- };
-
- FeatureSet() : features(MVP) {}
- FeatureSet(uint32_t features) : features(features) {}
-
- bool isMVP() const { return features == MVP; }
- bool has(Feature f) { return (features & f) == f; }
- bool hasAtomics() const { return features & Atomics; }
- bool hasMutableGlobals() const { return features & MutableGlobals; }
- bool hasTruncSat() const { return features & TruncSat; }
- bool hasSIMD() const { return features & SIMD; }
- bool hasBulkMemory() const { return features & BulkMemory; }
- bool hasAll() const { return features & All; }
-
- void makeMVP() { features = MVP; }
- void set(Feature f, bool v = true) { features = v ? (features | f) : (features & ~f); }
- void setAtomics(bool v = true) { set(Atomics, v); }
- void setMutableGlobals(bool v = true) { set(MutableGlobals, v); }
- void setTruncSat(bool v = true) { set(TruncSat, v); }
- void setSIMD(bool v = true) { set(SIMD, v); }
- void setBulkMemory(bool v = true) { set(BulkMemory, v); }
- void setAll(bool v = true) { features = v ? All : MVP; }
-
- bool operator<=(const FeatureSet& other) {
- return !(features & ~other.features);
- }
-
-private:
- uint32_t features;
-};
-
// An index in a wasm module
typedef uint32_t Index;
@@ -114,7 +75,6 @@ enum UnaryOp {
PromoteFloat32, // f32 to f64
DemoteFloat64, // f64 to f32
ReinterpretInt32, ReinterpretInt64, // reinterpret bits to float
- // The following sign-extention operators go along with wasm atomics support.
// Extend signed subword-sized integer. This differs from e.g. ExtendSInt32
// because the input integer is in an i64 value insetad of an i32 value.
ExtendS8Int32, ExtendS16Int32, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64,
@@ -268,7 +228,7 @@ public:
void finalize() {}
template<class T>
- bool is() {
+ bool is() const {
return int(_id) == int(T::SpecificId);
}
@@ -277,11 +237,22 @@ public:
return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
}
+ template <class T>
+ const T* dynCast() const {
+ return int(_id) == int(T::SpecificId) ? (const T*)this : nullptr;
+ }
+
template<class T>
T* cast() {
assert(int(_id) == int(T::SpecificId));
return (T*)this;
}
+
+ template<class T>
+ const T* cast() const {
+ assert(int(_id) == int(T::SpecificId));
+ return (const T*)this;
+ }
};
const char* getExpressionName(Expression* curr);
@@ -956,7 +927,7 @@ private:
std::map<Name, Global*> globalsMap;
public:
- Module() = default;;
+ Module() = default;
FunctionType* getFunctionType(Name name);
Export* getExport(Name name);
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index bc45f5834..b374566d1 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -243,7 +243,7 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
case Type::i64: o << literal.i64; break;
case Type::f32: literal.printFloat(o, literal.getf32()); break;
case Type::f64: literal.printDouble(o, literal.getf64()); break;
- case Type::v128: o << "i32 "; literal.printVec128(o, literal.getv128()); break;
+ case Type::v128: o << "i32x4 "; literal.printVec128(o, literal.getv128()); break;
case Type::unreachable: WASM_UNREACHABLE();
}
restoreNormalColor(o);
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index 390266d44..ea24b945d 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -47,10 +47,15 @@ void addExportedFunction(Module& wasm, Function* function) {
}
Global* EmscriptenGlueGenerator::getStackPointerGlobal() {
- // Assumption: first global is __stack_pointer
- // TODO(sbc): Once mutable globals are a thing we shouldn't need this
- // at all since we can simply export __stack_pointer.
- return wasm.globals[0].get();
+ // Assumption: The first non-imported global is global is __stack_pointer
+ // TODO(sbc): Find a better way to discover the stack pointer. Perhaps the
+ // linker could export it by name?
+ for (auto& g : wasm.globals) {
+ if (!g->imported()) {
+ return g.get();
+ }
+ }
+ Fatal() << "stack pointer global not found";
}
Expression* EmscriptenGlueGenerator::generateLoadStackPointer() {
@@ -157,6 +162,9 @@ Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
void EmscriptenGlueGenerator::generateStackInitialization(Address addr) {
auto* stackPointer = getStackPointerGlobal();
+ assert(!stackPointer->imported());
+ if (!stackPointer->init || !stackPointer->init->is<Const>())
+ Fatal() << "stack pointer global is not assignable";
stackPointer->init->cast<Const>()->value = Literal(int32_t(addr));
}
@@ -270,109 +278,6 @@ void EmscriptenGlueGenerator::replaceStackPointerGlobal() {
wasm.removeGlobal(stackPointer->name);
}
-struct JSCallWalker : public PostWalker<JSCallWalker> {
- Module &wasm;
- JSCallWalker(Module &_wasm) : wasm(_wasm) {
- if (wasm.table.segments.size() == 0) {
- auto emptySegment =
- wasm.allocator.alloc<Const>()->set(Literal(uint32_t(0)));
- wasm.table.segments.emplace_back(emptySegment);
- }
- const auto& tableSegmentData = wasm.table.segments[0].data;
-
- jsCallStartIndex =
- wasm.table.segments[0].offset->cast<Const>()->value.getInteger();
- // Check if jsCalls have already been created
- for (Index i = 0; i < tableSegmentData.size(); ++i) {
- if (tableSegmentData[i].startsWith("jsCall_")) {
- jsCallStartIndex += i;
- return;
- }
- }
- jsCallStartIndex += tableSegmentData.size();
- }
-
- // Gather all function signatures used in call_indirect, because any of them
- // can be used to call function pointers created by emscripten's addFunction.
- void visitCallIndirect(CallIndirect *curr) {
- // dynCall thunks are generated in binaryen and call_indirect instructions
- // within them cannot be used to call function pointers returned by
- // emscripten's addFunction.
- if (!getFunction()->name.startsWith("dynCall_")) {
- indirectlyCallableSigs.insert(
- getSig(wasm.getFunctionType(curr->fullType)));
- }
- }
-
- bool createJSCallThunks;
- Index jsCallStartIndex;
- // Function type signatures used in call_indirect instructions
- std::set<std::string> indirectlyCallableSigs;
-};
-
-JSCallWalker getJSCallWalker(Module& wasm) {
- JSCallWalker walker(wasm);
- walker.walkModule(&wasm);
- return walker;
-}
-
-void EmscriptenGlueGenerator::generateJSCallThunks(
- unsigned numReservedFunctionPointers) {
- if (numReservedFunctionPointers == 0)
- return;
-
- JSCallWalker walker = getJSCallWalker(wasm);
- auto& tableSegmentData = wasm.table.segments[0].data;
- unsigned numEntriesAdded = 0;
- for (std::string sig : walker.indirectlyCallableSigs) {
- // Add imports for jsCall_sig (e.g. jsCall_vi).
- // Imported jsCall_sig functions have their first parameter as an index to
- // the function table, so we should prepend an 'i' to parameters' signature
- // (e.g. If the signature of the callee is 'vi', the imported jsCall_vi
- // function would have signature 'vii'.)
- std::string importSig = std::string(1, sig[0]) + 'i' + sig.substr(1);
- FunctionType *importType = ensureFunctionType(importSig, &wasm);
- auto import = new Function;
- import->name = import->base = "jsCall_" + sig;
- import->module = ENV;
- import->type = importType->name;
- FunctionTypeUtils::fillFunction(import, importType);
- wasm.addFunction(import);
- FunctionType *funcType = ensureFunctionType(sig, &wasm);
-
- // Create jsCall_sig_index thunks (e.g. jsCall_vi_0, jsCall_vi_1, ...)
- // e.g. If # of reserved function pointers (given by a command line
- // argument) is 3 and there are two possible signature 'vi' and 'ii', the
- // genereated thunks will be jsCall_vi_0, jsCall_vi_1, jsCall_vi_2,
- // jsCall_ii_0, jsCall_ii_1, and jsCall_ii_2.
- for (unsigned fp = 0; fp < numReservedFunctionPointers; ++fp) {
- std::vector<NameType> params;
- int p = 0;
- for (const auto& ty : funcType->params) {
- params.emplace_back(std::to_string(p++), ty);
- }
- Function* f = builder.makeFunction(
- std::string("jsCall_") + sig + "_" + std::to_string(fp),
- std::move(params), funcType->result, {});
- std::vector<Expression*> args;
- args.push_back(builder.makeConst(Literal(fp)));
- for (unsigned i = 0; i < funcType->params.size(); ++i) {
- args.push_back(builder.makeGetLocal(i, funcType->params[i]));
- }
- Expression* call =
- builder.makeCall(import->name, args, funcType->result);
- f->body = call;
- wasm.addFunction(f);
- tableSegmentData.push_back(f->name);
- numEntriesAdded++;
- }
- }
- wasm.table.initial.addr += numEntriesAdded;
- if (wasm.table.max != Table::kUnlimitedSize) {
- wasm.table.max.addr += numEntriesAdded;
- }
-}
-
std::vector<Address> getSegmentOffsets(Module& wasm) {
std::vector<Address> segmentOffsets;
for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) {
@@ -780,8 +685,7 @@ void printSet(std::ostream& o, C& c) {
}
std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
- Address staticBump, std::vector<Name> const& initializerFunctions,
- unsigned numReservedFunctionPointers) {
+ Address staticBump, std::vector<Name> const& initializerFunctions) {
bool commaFirst;
auto nextElement = [&commaFirst]() {
if (commaFirst) {
@@ -844,18 +748,6 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
meta << "\n ],\n";
}
- if (numReservedFunctionPointers) {
- JSCallWalker jsCallWalker = getJSCallWalker(wasm);
- meta << " \"jsCallStartIndex\": " << jsCallWalker.jsCallStartIndex << ",\n";
- meta << " \"jsCallFuncType\": [";
- commaFirst = true;
- for (std::string sig : jsCallWalker.indirectlyCallableSigs) {
- meta << nextElement();
- meta << "\"" << sig << "\"";
- }
- meta << "\n ],\n";
- }
-
// Avoid adding duplicate imports to `declares' or `invokeFuncs`. Even
// though we might import the same function multiple times (i.e. with
// different sigs) we only need to list is in the metadata once.
@@ -870,8 +762,7 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
if (emJsWalker.codeByName.count(import->base.str) == 0 &&
!import->base.startsWith(EMSCRIPTEN_ASM_CONST.str) &&
- !import->base.startsWith("invoke_") &&
- !import->base.startsWith("jsCall_")) {
+ !import->base.startsWith("invoke_")) {
if (declares.insert(import->base.str).second) {
meta << nextElement() << '"' << import->base.str << '"';
}
diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp
index 95ffe6e89..057798d2e 100644
--- a/src/wasm/wasm-io.cpp
+++ b/src/wasm/wasm-io.cpp
@@ -30,18 +30,21 @@
namespace wasm {
-void ModuleReader::readText(std::string filename, Module& wasm) {
- if (debug) std::cerr << "reading text from " << filename << "\n";
- auto input(read_file<std::string>(filename, Flags::Text, debug ? Flags::Debug : Flags::Release));
+static void readTextData(std::string& input, Module& wasm) {
SExpressionParser parser(const_cast<char*>(input.c_str()));
Element& root = *parser.root;
SExpressionWasmBuilder builder(wasm, *root[0]);
+
}
-void ModuleReader::readBinary(std::string filename, Module& wasm,
- std::string sourceMapFilename) {
- if (debug) std::cerr << "reading binary from " << filename << "\n";
- auto input(read_file<std::vector<char>>(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release));
+void ModuleReader::readText(std::string filename, Module& wasm) {
+ if (debug) std::cerr << "reading text from " << filename << "\n";
+ auto input(read_file<std::string>(filename, Flags::Text, debug ? Flags::Debug : Flags::Release));
+ readTextData(input, wasm);
+}
+
+static void readBinaryData(std::vector<char>& input, Module& wasm,
+ std::string sourceMapFilename, bool debug) {
std::unique_ptr<std::ifstream> sourceMapStream;
WasmBinaryBuilder parser(wasm, input, debug);
if (sourceMapFilename.size()) {
@@ -55,6 +58,13 @@ void ModuleReader::readBinary(std::string filename, Module& wasm,
}
}
+void ModuleReader::readBinary(std::string filename, Module& wasm,
+ std::string sourceMapFilename) {
+ if (debug) std::cerr << "reading binary from " << filename << "\n";
+ auto input(read_file<std::vector<char>>(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release));
+ readBinaryData(input, wasm, sourceMapFilename, debug);
+}
+
bool ModuleReader::isBinaryFile(std::string filename) {
std::ifstream infile;
std::ios_base::openmode flags = std::ifstream::in | std::ifstream::binary;
@@ -67,6 +77,11 @@ bool ModuleReader::isBinaryFile(std::string filename) {
void ModuleReader::read(std::string filename, Module& wasm,
std::string sourceMapFilename) {
+ // empty filename means read from stdin
+ if (!filename.size()) {
+ readStdin(wasm, sourceMapFilename);
+ return;
+ }
if (isBinaryFile(filename)) {
readBinary(filename, wasm, sourceMapFilename);
} else {
@@ -78,6 +93,23 @@ void ModuleReader::read(std::string filename, Module& wasm,
}
}
+// TODO: reading into a vector<char> then copying into a string is unnecessarily
+// inefficient. It would be better to read just once into a stringstream.
+void ModuleReader::readStdin(Module& wasm, std::string sourceMapFilename) {
+ std::vector<char> input = read_stdin(debug ? Flags::Debug : Flags::Release);
+ if (input.size() >= 4 && input[0] == '\0' && input[1] == 'a' &&
+ input[2] == 's' && input[3] == 'm') {
+ readBinaryData(input, wasm, sourceMapFilename, debug);
+ } else {
+ std::ostringstream s;
+ s.write(input.data(), input.size());
+ s << '\0';
+ std::string input_str = s.str();
+ readTextData(input_str, wasm);
+ }
+}
+
+
void ModuleWriter::writeText(Module& wasm, Output& output) {
WasmPrinter::printModule(&wasm, output.getStream());
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 7fd4679b1..1067264f7 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -641,6 +641,16 @@ Type SExpressionWasmBuilder::stringToType(const char* str, bool allowError, bool
throw ParseException("invalid wasm type");
}
+Type SExpressionWasmBuilder::stringToLaneType(const char* str) {
+ if (strcmp(str, "i8x16") == 0) return i32;
+ if (strcmp(str, "i16x8") == 0) return i32;
+ if (strcmp(str, "i32x4") == 0) return i32;
+ if (strcmp(str, "i64x2") == 0) return i64;
+ if (strcmp(str, "f32x4") == 0) return f32;
+ if (strcmp(str, "f64x2") == 0) return f64;
+ return none;
+}
+
Function::DebugLocation SExpressionWasmBuilder::getDebugLocation(const SourceLocation& loc) {
IString file = loc.filename;
auto& debugInfoFileNames = wasm.debugInfoFileNames;
@@ -864,6 +874,20 @@ Expression* SExpressionWasmBuilder::makeThenOrElse(Element& s) {
return ret;
}
+template<int Lanes>
+static Literal makeLanes(Element& s, MixedArena& allocator, Type lane_t) {
+ std::array<Literal, Lanes> lanes;
+ for (size_t i = 0; i < Lanes; ++i) {
+ Expression* lane = parseConst(s[i+2]->str(), lane_t, allocator);
+ if (lane) {
+ lanes[i] = lane->cast<Const>()->value;
+ } else {
+ throw ParseException("Could not parse v128 lane");
+ }
+ }
+ return Literal(lanes);
+}
+
Expression* SExpressionWasmBuilder::makeConst(Element& s, Type type) {
if (type != v128) {
auto ret = parseConst(s[1]->str(), type, allocator);
@@ -872,57 +896,35 @@ Expression* SExpressionWasmBuilder::makeConst(Element& s, Type type) {
}
auto ret = allocator.alloc<Const>();
- auto getLiteral = [](Expression* expr) {
- if (expr == nullptr) {
- throw ParseException("Could not parse v128 lane");
- }
- return expr->cast<Const>()->value;
- };
- Type lane_t = stringToType(s[1]->str());
+ Type lane_t = stringToLaneType(s[1]->str().str);
size_t lanes = s.size() - 2;
switch (lanes) {
case 2: {
if (lane_t != i64 && lane_t != f64) {
throw ParseException("Unexpected v128 literal lane type");
}
- std::array<Literal, 2> lanes;
- for (size_t i = 0; i < 2; ++i) {
- lanes[i] = getLiteral(parseConst(s[i+2]->str(), lane_t, allocator));
- }
- ret->value = Literal(lanes);
+ ret->value = makeLanes<2>(s, allocator, lane_t);
break;
}
case 4: {
if (lane_t != i32 && lane_t != f32) {
throw ParseException("Unexpected v128 literal lane type");
}
- std::array<Literal, 4> lanes;
- for (size_t i = 0; i < 4; ++i) {
- lanes[i] = getLiteral(parseConst(s[i+2]->str(), lane_t, allocator));
- }
- ret->value = Literal(lanes);
+ ret->value = makeLanes<4>(s, allocator, lane_t);
break;
}
case 8: {
if (lane_t != i32) {
throw ParseException("Unexpected v128 literal lane type");
}
- std::array<Literal, 8> lanes;
- for (size_t i = 0; i < 8; ++i) {
- lanes[i] = getLiteral(parseConst(s[i+2]->str(), lane_t, allocator));
- }
- ret->value = Literal(lanes);
+ ret->value = makeLanes<8>(s, allocator, lane_t);
break;
}
case 16: {
if (lane_t != i32) {
throw ParseException("Unexpected v128 literal lane type");
}
- std::array<Literal, 16> lanes;
- for (size_t i = 0; i < 16; ++i) {
- lanes[i] = getLiteral(parseConst(s[i+2]->str(), lane_t, allocator));
- }
- ret->value = Literal(lanes);
+ ret->value = makeLanes<16>(s, allocator, lane_t);
break;
}
default: throw ParseException("Unexpected number of lanes in v128 literal");
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index f9371ffab..fc393ed98 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -15,6 +15,7 @@
*/
#include "wasm-type.h"
+#include "wasm-features.h"
#include <cstdlib>
#include "compiler-support.h"
@@ -47,6 +48,13 @@ unsigned getTypeSize(Type type) {
WASM_UNREACHABLE();
}
+FeatureSet getFeatures(Type type) {
+ if (type == v128) {
+ return FeatureSet::SIMD;
+ }
+ return FeatureSet();
+}
+
Type getType(unsigned size, bool float_) {
if (size < 4) return Type::i32;
if (size == 4) return float_ ? Type::f32 : Type::i32;
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 84a0efbff..91e7e7398 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -1081,12 +1081,17 @@ void FunctionValidator::visitHost(Host* curr) {
}
void FunctionValidator::visitFunction(Function* curr) {
+ FeatureSet typeFeatures = getFeatures(curr->result);
for (auto type : curr->params) {
+ typeFeatures |= getFeatures(type);
shouldBeTrue(isConcreteType(type), curr, "params must be concretely typed");
}
for (auto type : curr->vars) {
+ typeFeatures |= getFeatures(type);
shouldBeTrue(isConcreteType(type), curr, "vars must be concretely typed");
}
+ shouldBeTrue(typeFeatures <= info.features, curr,
+ "all used types should be allowed");
// if function has no result, it is ignored
// if body is unreachable, it might be e.g. a return
if (curr->body->type != unreachable) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index c12481760..c99bb0994 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -32,6 +32,7 @@ const char* SourceMapUrl = "sourceMappingURL";
const char* Dylink = "dylink";
const char* Linking = "linking";
const char* Producers = "producers";
+const char* TargetFeatures = "target_features";
}
}