- Revision
- 189303
- Author
- [email protected]
- Date
- 2015-09-03 15:45:03 -0700 (Thu, 03 Sep 2015)
Log Message
Implement some arithmetic instructions in WebAssembly
https://bugs.webkit.org/show_bug.cgi?id=148737
Patch by Sukolsak Sakshuwong <[email protected]> on 2015-09-03
Reviewed by Geoffrey Garen.
This patch implements the addition and subtraction instructions in
WebAssembly using a stack-based approach: each instruction reads its
operands from the top of the 'temporary' stack, pops them, and
optionally pushes a return value to the stack. Since operands are passed
on the stack, we don't use the arguments that are passed to the methods
of WASMFunctionCompiler, and we don't use the return values from these
methods. (We will use them when we implement LLVM IR generation for
WebAssembly, where each _expression_ is an LLVMValueRef.)
* tests/stress/wasm-arithmetic.js: Added.
* tests/stress/wasm-arithmetic.wasm: Added.
* wasm/WASMFunctionCompiler.h:
(JSC::WASMFunctionCompiler::endFunction):
(JSC::WASMFunctionCompiler::buildReturn):
(JSC::WASMFunctionCompiler::buildImmediateI32):
(JSC::WASMFunctionCompiler::buildBinaryI32):
(JSC::WASMFunctionCompiler::temporaryAddress):
* wasm/WASMFunctionParser.cpp:
(JSC::WASMFunctionParser::parseReturnStatement):
(JSC::WASMFunctionParser::parseExpressionI32):
(JSC::WASMFunctionParser::parseImmediateExpressionI32):
(JSC::WASMFunctionParser::parseBinaryExpressionI32):
* wasm/WASMFunctionParser.h:
* wasm/WASMFunctionSyntaxChecker.h:
(JSC::WASMFunctionSyntaxChecker::startFunction):
(JSC::WASMFunctionSyntaxChecker::endFunction):
(JSC::WASMFunctionSyntaxChecker::buildReturn):
(JSC::WASMFunctionSyntaxChecker::buildImmediateI32):
(JSC::WASMFunctionSyntaxChecker::buildBinaryI32):
(JSC::WASMFunctionSyntaxChecker::stackHeight):
(JSC::WASMFunctionSyntaxChecker::updateTempStackHeight):
Modified Paths
Added Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (189302 => 189303)
--- trunk/Source/_javascript_Core/ChangeLog 2015-09-03 22:39:38 UTC (rev 189302)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-09-03 22:45:03 UTC (rev 189303)
@@ -1,3 +1,42 @@
+2015-09-03 Sukolsak Sakshuwong <[email protected]>
+
+ Implement some arithmetic instructions in WebAssembly
+ https://bugs.webkit.org/show_bug.cgi?id=148737
+
+ Reviewed by Geoffrey Garen.
+
+ This patch implements the addition and subtraction instructions in
+ WebAssembly using a stack-based approach: each instruction reads its
+ operands from the top of the 'temporary' stack, pops them, and
+ optionally pushes a return value to the stack. Since operands are passed
+ on the stack, we don't use the arguments that are passed to the methods
+ of WASMFunctionCompiler, and we don't use the return values from these
+ methods. (We will use them when we implement LLVM IR generation for
+ WebAssembly, where each _expression_ is an LLVMValueRef.)
+
+ * tests/stress/wasm-arithmetic.js: Added.
+ * tests/stress/wasm-arithmetic.wasm: Added.
+ * wasm/WASMFunctionCompiler.h:
+ (JSC::WASMFunctionCompiler::endFunction):
+ (JSC::WASMFunctionCompiler::buildReturn):
+ (JSC::WASMFunctionCompiler::buildImmediateI32):
+ (JSC::WASMFunctionCompiler::buildBinaryI32):
+ (JSC::WASMFunctionCompiler::temporaryAddress):
+ * wasm/WASMFunctionParser.cpp:
+ (JSC::WASMFunctionParser::parseReturnStatement):
+ (JSC::WASMFunctionParser::parseExpressionI32):
+ (JSC::WASMFunctionParser::parseImmediateExpressionI32):
+ (JSC::WASMFunctionParser::parseBinaryExpressionI32):
+ * wasm/WASMFunctionParser.h:
+ * wasm/WASMFunctionSyntaxChecker.h:
+ (JSC::WASMFunctionSyntaxChecker::startFunction):
+ (JSC::WASMFunctionSyntaxChecker::endFunction):
+ (JSC::WASMFunctionSyntaxChecker::buildReturn):
+ (JSC::WASMFunctionSyntaxChecker::buildImmediateI32):
+ (JSC::WASMFunctionSyntaxChecker::buildBinaryI32):
+ (JSC::WASMFunctionSyntaxChecker::stackHeight):
+ (JSC::WASMFunctionSyntaxChecker::updateTempStackHeight):
+
2015-09-03 Brian Burg <[email protected]>
Web Inspector: should crash on purpose if InjectedScriptSource.js is unparseable
Added: trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic.js (0 => 189303)
--- trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic.js 2015-09-03 22:45:03 UTC (rev 189303)
@@ -0,0 +1,22 @@
+//@ skip
+
+/*
+wasm-arithmetic.wasm is generated by pack-asmjs <https://github.com/WebAssembly/polyfill-prototype-1> from the following script:
+
+function asmModule(global, env, buffer) {
+ "use asm";
+
+ function main() {
+ return (10 + 40) - 8;
+ }
+
+ return {
+ main: main
+ };
+}
+*/
+
+var module = loadWebAssembly("wasm-arithmetic.wasm");
+var result = module.main();
+if (result != 42)
+ throw "Error: bad result: " + result;
Added: trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic.wasm (0 => 189303)
--- trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic.wasm (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic.wasm 2015-09-03 22:45:03 UTC (rev 189303)
@@ -0,0 +1 @@
+wasm\xF8\x80\xAA(\xA8main
\ No newline at end of file
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h (189302 => 189303)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h 2015-09-03 22:39:38 UTC (rev 189302)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h 2015-09-03 22:45:03 UTC (rev 189303)
@@ -33,6 +33,8 @@
#include "LinkBuffer.h"
#include "MaxFrameExtentForSlowPathCall.h"
+#define UNUSED 0
+
namespace JSC {
class WASMFunctionCompiler : private CCallHelpers {
@@ -40,12 +42,6 @@
typedef int _expression_;
typedef int Statement;
- union StackSlot {
- int32_t intValue;
- float floatValue;
- double doubleValue;
- };
-
WASMFunctionCompiler(VM& vm, CodeBlock* codeBlock, unsigned stackHeight)
: CCallHelpers(&vm, codeBlock)
, m_stackHeight(stackHeight)
@@ -102,6 +98,8 @@
void endFunction()
{
+ ASSERT(!m_tempStackTop);
+
// FIXME: Remove these if the last statement is a return statement.
move(TrustedImm64(JSValue::encode(jsUndefined())), GPRInfo::returnValueGPR);
emitFunctionEpilogue();
@@ -129,13 +127,68 @@
m_codeBlock->capabilityLevel();
}
+ void buildReturn(int, WASMExpressionType returnType)
+ {
+ switch (returnType) {
+ case WASMExpressionType::I32:
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::returnValueGPR);
+ or64(GPRInfo::tagTypeNumberRegister, GPRInfo::returnValueGPR);
+ m_tempStackTop--;
+ break;
+ case WASMExpressionType::Void:
+ move(TrustedImm64(JSValue::encode(jsUndefined())), GPRInfo::returnValueGPR);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ emitFunctionEpilogue();
+ ret();
+ }
+
+ int buildImmediateI32(uint32_t immediate)
+ {
+ store32(TrustedImm32(immediate), temporaryAddress(m_tempStackTop++));
+ return UNUSED;
+ }
+
+ int buildBinaryI32(int, int, WASMOpExpressionI32 op)
+ {
+ load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ switch (op) {
+ case WASMOpExpressionI32::Add:
+ add32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::Sub:
+ sub32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ m_tempStackTop--;
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
private:
+ union StackSlot {
+ int32_t intValue;
+ float floatValue;
+ double doubleValue;
+ };
+
Address localAddress(unsigned localIndex) const
{
ASSERT(localIndex < m_numberOfLocals);
return Address(GPRInfo::callFrameRegister, -(localIndex + 1) * sizeof(StackSlot));
}
+ Address temporaryAddress(unsigned temporaryIndex) const
+ {
+ ASSERT(m_numberOfLocals + temporaryIndex < m_stackHeight);
+ return Address(GPRInfo::callFrameRegister, -(m_numberOfLocals + temporaryIndex + 1) * sizeof(StackSlot));
+ }
+
void throwStackOverflowError()
{
setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock));
@@ -156,6 +209,7 @@
unsigned m_stackHeight;
unsigned m_numberOfLocals;
+ unsigned m_tempStackTop { 0 };
Label m_beginLabel;
Jump m_stackOverflow;
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp (189302 => 189303)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp 2015-09-03 22:39:38 UTC (rev 189302)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp 2015-09-03 22:45:03 UTC (rev 189303)
@@ -226,9 +226,12 @@
template <class Context>
ContextStatement WASMFunctionParser::parseReturnStatement(Context& context)
{
- if (m_returnType != WASMExpressionType::Void)
- parseExpression(context, m_returnType);
- // FIXME: Implement this instruction.
+ ContextExpression _expression_ = 0;
+ if (m_returnType != WASMExpressionType::Void) {
+ _expression_ = parseExpression(context, m_returnType);
+ PROPAGATE_ERROR();
+ }
+ context.buildReturn(_expression_, m_returnType);
return UNUSED;
}
@@ -422,6 +425,9 @@
switch (op) {
case WASMOpExpressionI32::Immediate:
return parseImmediateExpressionI32(context);
+ case WASMOpExpressionI32::Add:
+ case WASMOpExpressionI32::Sub:
+ return parseBinaryExpressionI32(context, op);
case WASMOpExpressionI32::ConstantPoolIndex:
case WASMOpExpressionI32::GetLocal:
case WASMOpExpressionI32::GetGlobal:
@@ -451,8 +457,6 @@
case WASMOpExpressionI32::FromF32:
case WASMOpExpressionI32::FromF64:
case WASMOpExpressionI32::Negate:
- case WASMOpExpressionI32::Add:
- case WASMOpExpressionI32::Sub:
case WASMOpExpressionI32::Mul:
case WASMOpExpressionI32::SDiv:
case WASMOpExpressionI32::UDiv:
@@ -515,10 +519,9 @@
}
template <class Context>
-ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context&, uint32_t)
+ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context& context, uint32_t immediate)
{
- // FIXME: Implement this instruction.
- return UNUSED;
+ return context.buildImmediateI32(immediate);
}
template <class Context>
@@ -529,6 +532,16 @@
return parseImmediateExpressionI32(context, immediate);
}
+template <class Context>
+ContextExpression WASMFunctionParser::parseBinaryExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ ContextExpression left = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ return context.buildBinaryI32(left, right, op);
+}
+
} // namespace JSC
#endif // ENABLE(WEBASSEMBLY)
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h (189302 => 189303)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h 2015-09-03 22:39:38 UTC (rev 189302)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h 2015-09-03 22:45:03 UTC (rev 189303)
@@ -80,6 +80,7 @@
template <class Context> ContextExpression parseExpressionI32(Context&);
template <class Context> ContextExpression parseImmediateExpressionI32(Context&, uint32_t immediate);
template <class Context> ContextExpression parseImmediateExpressionI32(Context&);
+ template <class Context> ContextExpression parseBinaryExpressionI32(Context&, WASMOpExpressionI32);
JSWASMModule* m_module;
WASMReader m_reader;
Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h (189302 => 189303)
--- trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h 2015-09-03 22:39:38 UTC (rev 189302)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h 2015-09-03 22:45:03 UTC (rev 189303)
@@ -28,6 +28,8 @@
#if ENABLE(WEBASSEMBLY)
+#define UNUSED 0
+
namespace JSC {
class WASMFunctionSyntaxChecker {
@@ -37,16 +39,48 @@
void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
{
- // FIXME: Need to include the number of temporaries used.
- m_stackHeight = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
+ m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
}
- void endFunction() { }
+ void endFunction()
+ {
+ ASSERT(!m_tempStackTop);
+ }
- unsigned stackHeight() { return m_stackHeight; }
+ void buildReturn(int, WASMExpressionType returnType)
+ {
+ if (returnType != WASMExpressionType::Void)
+ m_tempStackTop--;
+ }
+ int buildImmediateI32(uint32_t)
+ {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ return UNUSED;
+ }
+
+ int buildBinaryI32(int, int, WASMOpExpressionI32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ unsigned stackHeight()
+ {
+ return m_numberOfLocals + m_tempStackHeight;
+ }
+
private:
- unsigned m_stackHeight;
+ void updateTempStackHeight()
+ {
+ if (m_tempStackTop > m_tempStackHeight)
+ m_tempStackHeight = m_tempStackTop;
+ }
+
+ unsigned m_numberOfLocals;
+ unsigned m_tempStackTop { 0 };
+ unsigned m_tempStackHeight { 0 };
};
} // namespace JSC