Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (189598 => 189599)
--- trunk/Source/_javascript_Core/ChangeLog 2015-09-11 00:55:14 UTC (rev 189598)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-09-11 01:37:09 UTC (rev 189599)
@@ -1,3 +1,22 @@
+2015-09-10 Sukolsak Sakshuwong <[email protected]>
+
+ Implement switch statements in WebAssembly
+ https://bugs.webkit.org/show_bug.cgi?id=149051
+
+ Reviewed by Geoffrey Garen.
+
+ This patch implements switch statements in WebAssembly using the
+ JSC::BinarySwitch class.
+
+ * tests/stress/wasm-control-flow.js:
+ * tests/stress/wasm/control-flow.wasm:
+ * wasm/WASMFunctionCompiler.h:
+ (JSC::WASMFunctionCompiler::buildSwitch):
+ * wasm/WASMFunctionParser.cpp:
+ (JSC::WASMFunctionParser::parseSwitchStatement):
+ * wasm/WASMFunctionSyntaxChecker.h:
+ (JSC::WASMFunctionSyntaxChecker::buildSwitch):
+
2015-09-10 Filip Pizlo <[email protected]>
Structure should be able to tell you if it had ever been a dictionary
Modified: trunk/Source/_javascript_Core/tests/stress/wasm/control-flow.wasm (189598 => 189599)
--- trunk/Source/_javascript_Core/tests/stress/wasm/control-flow.wasm 2015-09-11 00:55:14 UTC (rev 189598)
+++ trunk/Source/_javascript_Core/tests/stress/wasm/control-flow.wasm 2015-09-11 01:37:09 UTC (rev 189599)
@@ -1,4 +1,3 @@
-wasm
-\x81\x80\xA5<\xC0\xA0\xA1\xA0\x81<\xC0\xA0\xA1\xA0\x81\x80\xA5<\xC0\xA0\xA1\xA2\x81<\xC0\xA0\xA1\xA2\x82\x80\xA1.\xC0\xA0.\xC1\xA0\xA1\xA2.\xC1\xA0\xA3\xA4\x824\xC1\xA5\x80\xC0\xA1\x81\xC1\xA1\xC0\x82\xA1.\xC1\xA2\x80\xC0\xA1\x81\xC1\xA1\xC0\x824\xC1\xA5.\xC1\xA2\x81\xA3\x80\xC0\xA1\x81\xC1\xA1\xC0\x834\xC1\xA5\x82\xA04¢\x80\xC0\xA1\x82¡\x81\xC1\xA1\xC0\x82\x80\xC0\xA1\x81\xC1\xA14\xC1\xA0\xC0\x82.\xC1\xA2\x80\xC0\xA1\x81\xC1\xA1\xA1\xC0\x82.\xC1\xA2\x81\xA3\x80\xC0\xA1\x81\xC1\xA14\xC1\xA5\xC0\x81\x80\xA1\x80\xA2\xA0\xC0\x81.\xC0\xA1\x80\xA1\x80\xA2\xA0\xC0\x81\x80\xA1\x80\xA2\x80\xA3\xA0\x80\xA4\xA0\xC0\x81\x80\xA1\x80\xA2\x80\xA3\xA0\x80\xA4\xA0\xC0\x834\xC1\xA5\x82\xA04¢\x80\xC0\xA1.\xC0\xA8\x82¡\x81\xC1\xA1\xC0ifTrueifFalseifElseTrueifElseFalseifInIfwhileLoop
whileBreakwhileContinuewhileInWhiledoLoop doBreak
+wasm6\x81\x80\xA5<\xC0\xA0\xA1\xA0\x81<\xC0\xA0\xA1\xA0\x81\x80\xA5<\xC0\xA0\xA1\xA2\x81<\xC0\xA0\xA1\xA2\x82\x80\xA1.\xC0\xA0.\xC1\xA0\xA1\xA2.\xC1\xA0\xA3\xA4\x824\xC1\xA5\x80\xC0\xA1\x81\xC1\xA1\xC0\x82\xA1.\xC1\xA2\x80\xC0\xA1\x81\xC1\xA1\xC0\x824\xC1\xA5.\xC1\xA2\x81\xA3\x80\xC0\xA1\x81\xC1\xA1\xC0\x834\xC1\xA5\x82\xA04¢\x80\xC0\xA1\x82¡\x81\xC1\xA1\xC0\x82\x80\xC0\xA1\x81\xC1\xA14\xC1\xA0\xC0\x82.\xC1\xA2\x80\xC0\xA1\x81\xC1\xA1\xA1\xC0\x82.\xC1\xA2\x81\xA3\x80\xC0\xA1\x81\xC1\xA14\xC1\xA5\xC0\x81\x80\xA1\x80\xA2\xA0\xC0\x81.\xC0\xA1\x80\xA1\x80\xA2\xA0\xC0\x81\x80\xA1\x80\xA2\x80\xA3\xA0\x80\xA4\xA0\xC0\x81\x80\xA1\x80\xA2\x80\xA3\xA0\x80\xA4\xA0\xC0\x834\xC1\xA5\x82\xA04¢\x80\xC0\xA1.\xC0\xA8\x82¡\x81\xC1\xA1\xC0\x81\xC0\x81\xA1\x81\xA2\x
81\xA3\xC1\x81\xC0\x81\xC1\xE8\x81\xC1d\x81\xC1\xAA\x81\xC1\xA1\xC1ifTrueifFalseifElseTrueifElseFalseifInIfwhileLoopwhileBreakwhileContinuewhileInWhiledoLoop doBreak
doContinuelabelBreaklabelContinue-labelInLabelBreakInnerlabelInLabelBreakOuterwhileInWhileBreakOuter
\ No newline at end of file
+labelInLabelBreakInnerlabelInLabelBreakOuterwhileInWhileBreakOuterswitchCaseswitchFallThrough
\ No newline at end of file
Modified: trunk/Source/_javascript_Core/tests/stress/wasm-control-flow.js (189598 => 189599)
--- trunk/Source/_javascript_Core/tests/stress/wasm-control-flow.js 2015-09-11 00:55:14 UTC (rev 189598)
+++ trunk/Source/_javascript_Core/tests/stress/wasm-control-flow.js 2015-09-11 01:37:09 UTC (rev 189599)
@@ -204,6 +204,39 @@
return x;
}
+ function switchCase(x) {
+ x = x | 0;
+ var y = 0;
+ switch (x) {
+ case 0:
+ y = 1;
+ break;
+ case 1:
+ y = 2;
+ break;
+ case 2:
+ y = 3;
+ break;
+ }
+ return y;
+ }
+
+ function switchFallThrough(x) {
+ x = x | 0;
+ var y = 0;
+ switch (x) {
+ case 3:
+ y = (y + 1000) | 0;
+ case 2:
+ y = (y + 100) | 0;
+ case 1:
+ y = (y + 10) | 0;
+ default:
+ y = (y + 1) | 0;
+ }
+ return y;
+ }
+
return {
ifTrue: ifTrue,
ifFalse: ifFalse,
@@ -222,6 +255,8 @@
labelInLabelBreakInner: labelInLabelBreakInner,
labelInLabelBreakOuter: labelInLabelBreakOuter,
whileInWhileBreakOuter: whileInWhileBreakOuter,
+ switchCase: switchCase,
+ switchFallThrough: switchFallThrough,
};
}
*/
@@ -233,15 +268,28 @@
shouldBe(module.ifElseTrue(), 1);
shouldBe(module.ifElseFalse(), 2);
shouldBe(module.ifInIf(), 3);
+
shouldBe(module.whileLoop(), 5);
shouldBe(module.whileBreak(), 2);
shouldBe(module.whileContinue(), 4);
shouldBe(module.whileInWhile(), 10);
+
shouldBe(module.doLoop(), 1);
shouldBe(module.doBreak(), 2);
shouldBe(module.doContinue(), 4);
+
shouldBe(module.labelBreak(), 1);
shouldBe(module.labelContinue(), 1);
shouldBe(module.labelInLabelBreakInner(), 4);
shouldBe(module.labelInLabelBreakOuter(), 2);
shouldBe(module.whileInWhileBreakOuter(), 8);
+
+shouldBe(module.switchCase(0), 1);
+shouldBe(module.switchCase(1), 2);
+shouldBe(module.switchCase(2), 3);
+shouldBe(module.switchCase(3), 0);
+shouldBe(module.switchFallThrough(0), 1);
+shouldBe(module.switchFallThrough(1), 11);
+shouldBe(module.switchFallThrough(2), 111);
+shouldBe(module.switchFallThrough(3), 1111);
+shouldBe(module.switchFallThrough(4), 1);
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h (189598 => 189599)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h 2015-09-11 00:55:14 UTC (rev 189598)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h 2015-09-11 01:37:09 UTC (rev 189599)
@@ -28,6 +28,7 @@
#if ENABLE(WEBASSEMBLY)
+#include "BinarySwitch.h"
#include "CCallHelpers.h"
#include "JIT.h"
#include "JITOperations.h"
@@ -634,6 +635,18 @@
return m_continueLabelTargets[labelIndex];
}
+ void buildSwitch(int, const Vector<int64_t>& cases, Vector<JumpTarget>& targets, JumpTarget defaultTarget)
+ {
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
+ m_tempStackTop--;
+ BinarySwitch binarySwitch(GPRInfo::regT0, cases, BinarySwitch::Int32);
+ while (binarySwitch.advance(*this)) {
+ unsigned index = binarySwitch.caseIndex();
+ jump(targets[index].label);
+ }
+ binarySwitch.fallThrough().linkTo(defaultTarget.label, this);
+ }
+
private:
union StackSlot {
int32_t intValue;
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp (189598 => 189599)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp 2015-09-11 00:55:14 UTC (rev 189598)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp 2015-09-11 01:37:09 UTC (rev 189599)
@@ -415,11 +415,22 @@
template <class Context>
ContextStatement WASMFunctionParser::parseSwitchStatement(Context& context)
{
+ context.startSwitch();
uint32_t numberOfCases;
READ_COMPACT_UINT32_OR_FAIL(numberOfCases, "Cannot read the number of cases.");
- parseExpressionI32(context);
+ ContextExpression _expression_ = parseExpressionI32(context);
PROPAGATE_ERROR();
+ ContextJumpTarget compare;
+ context.jumpToTarget(compare);
+
+ Vector<int64_t> cases;
+ Vector<ContextJumpTarget> targets;
+ cases.reserveInitialCapacity(numberOfCases);
+ targets.reserveInitialCapacity(numberOfCases);
+ bool hasDefault = false;
+ ContextJumpTarget defaultTarget;
+
m_breakScopeDepth++;
for (uint32_t i = 0; i < numberOfCases; ++i) {
WASMSwitchCase switchCase;
@@ -430,6 +441,10 @@
case WASMSwitchCase::CaseWithBlockStatement: {
uint32_t value;
READ_COMPACT_INT32_OR_FAIL(value, "Cannot read the value of the switch case.");
+ cases.uncheckedAppend(value);
+ ContextJumpTarget target;
+ context.linkTarget(target);
+ targets.uncheckedAppend(target);
if (switchCase == WASMSwitchCase::CaseWithStatement) {
parseStatement(context);
PROPAGATE_ERROR();
@@ -443,6 +458,8 @@
case WASMSwitchCase::DefaultWithStatement:
case WASMSwitchCase::DefaultWithBlockStatement: {
FAIL_IF_FALSE(i == numberOfCases - 1, "The default case must be the last case.");
+ hasDefault = true;
+ context.linkTarget(defaultTarget);
if (switchCase == WASMSwitchCase::DefaultWithStatement) {
parseStatement(context);
PROPAGATE_ERROR();
@@ -456,8 +473,18 @@
ASSERT_NOT_REACHED();
}
}
+ if (!hasDefault)
+ context.linkTarget(defaultTarget);
+
m_breakScopeDepth--;
- // FIXME: Implement this instruction.
+
+ context.jumpToTarget(context.breakTarget());
+ context.linkTarget(compare);
+
+ context.buildSwitch(_expression_, cases, targets, defaultTarget);
+
+ context.linkTarget(context.breakTarget());
+ context.endSwitch();
return UNUSED;
}
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h (189598 => 189599)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h 2015-09-11 00:55:14 UTC (rev 189598)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h 2015-09-11 01:37:09 UTC (rev 189599)
@@ -155,6 +155,11 @@
int breakLabelTarget(uint32_t) { return UNUSED; }
int continueLabelTarget(uint32_t) { return UNUSED; }
+ void buildSwitch(int, const Vector<int64_t>&, const Vector<int>&, const int&)
+ {
+ m_tempStackTop--;
+ }
+
unsigned stackHeight()
{
return m_numberOfLocals + m_tempStackHeight;