Bug 1279248 - Part 24: Make WebAssembly ready to run 64bit instructions on x86, r=luke
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:48 +0200
changeset 332379 346f051f5978d60b4e716a5a6d6b9d4d2415892f
parent 332378 fa0c24a5b89db6f14730eb4d94acd21408bfccc1
child 332380 bb7803606205b1d23590fa05d78c384b833f614d
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1279248
milestone50.0a1
Bug 1279248 - Part 24: Make WebAssembly ready to run 64bit instructions on x86, r=luke
js/src/asmjs/WasmCompile.cpp
js/src/asmjs/WasmJS.cpp
js/src/asmjs/WasmJS.h
js/src/asmjs/WasmStubs.cpp
js/src/builtin/TestingFunctions.cpp
js/src/jit-test/lib/wasm.js
--- a/js/src/asmjs/WasmCompile.cpp
+++ b/js/src/asmjs/WasmCompile.cpp
@@ -35,26 +35,16 @@ using mozilla::IsNaN;
 static bool
 Fail(Decoder& d, const char* str)
 {
     uint32_t offset = d.currentOffset();
     d.fail(UniqueChars(JS_smprintf("compile error at offset %" PRIu32 ": %s", offset, str)));
     return false;
 }
 
-static bool
-IsI64Implemented()
-{
-#ifdef JS_CPU_X64
-    return true;
-#else
-    return false;
-#endif
-}
-
 namespace {
 
 struct ValidatingPolicy : ExprIterPolicy
 {
     // Validation is what we're all about here.
     static const bool Validate = true;
 };
 
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -57,16 +57,26 @@ CheckCompilerSupport(JSContext* cx)
 #endif
         JS_ReportError(cx, "WebAssembly is not supported on the current device.");
         return false;
     }
 
     return true;
 }
 
+bool
+wasm::IsI64Implemented()
+{
+#if defined(JS_CPU_X64) || defined(JS_CODEGEN_X86)
+    return true;
+#else
+    return false;
+#endif
+}
+
 // ============================================================================
 // (Temporary) Wasm class and static methods
 
 static bool
 Throw(JSContext* cx, const char* str)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL, str);
     return false;
--- a/js/src/asmjs/WasmJS.h
+++ b/js/src/asmjs/WasmJS.h
@@ -40,16 +40,20 @@ typedef UniquePtr<Instance> UniqueInstan
 
 // Return whether WebAssembly can be compiled on this platform.
 // This must be checked and must be true to call any of the top-level wasm
 // eval/compile methods.
 
 bool
 HasCompilerSupport(ExclusiveContext* cx);
 
+// Return whether WebAssembly has int64 support on this platform.
+bool
+IsI64Implemented();
+
 // Compiles the given binary wasm module given the ArrayBufferObject
 // and links the module's imports with the given import object.
 
 MOZ_MUST_USE bool
 Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj,
      MutableHandle<WasmInstanceObject*> instanceObj);
 
 // The field name of the export object on the instance object.
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -146,17 +146,16 @@ wasm::GenerateEntry(MacroAssembler& masm
     MOZ_ASSERT(WasmTlsReg != ABINonArgReg1, "TLS pointer can't be scratch reg");
 
     // Put the 'argv' argument into a non-argument/return register so that we
     // can use 'argv' while we fill in the arguments for the asm.js callee.
     // Also, save 'argv' on the stack so that we can recover it after the call.
     // Use a second non-argument/return register as temporary scratch.
     Register argv = ABINonArgReturnReg0;
     Register scratch = ABINonArgReturnReg1;
-    Register64 scratch64(scratch);
 
 #if defined(JS_CODEGEN_X86)
     masm.loadPtr(Address(masm.getStackPointer(), EntryFrameSize + masm.framePushed()), argv);
 #else
     masm.movePtr(IntArgReg0, argv);
 #endif
     masm.Push(argv);
 
@@ -223,20 +222,30 @@ wasm::GenerateEntry(MacroAssembler& masm
             break;
           }
           case ABIArg::Stack:
             switch (type) {
               case MIRType::Int32:
                 masm.load32(src, scratch);
                 masm.storePtr(scratch, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
                 break;
-              case MIRType::Int64:
+              case MIRType::Int64: {
+                Register sp = masm.getStackPointer();
+#if JS_BITS_PER_WORD == 32
+                masm.load32(Address(src.base, src.offset + INT64LOW_OFFSET), scratch);
+                masm.store32(scratch, Address(sp, iter->offsetFromArgBase() + INT64LOW_OFFSET));
+                masm.load32(Address(src.base, src.offset + INT64HIGH_OFFSET), scratch);
+                masm.store32(scratch, Address(sp, iter->offsetFromArgBase() + INT64HIGH_OFFSET));
+#else
+                Register64 scratch64(scratch);
                 masm.load64(src, scratch64);
-                masm.store64(scratch64, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
+                masm.store64(scratch64, Address(sp, iter->offsetFromArgBase()));
+#endif
                 break;
+              }
               case MIRType::Double:
                 masm.loadDouble(src, ScratchDoubleReg);
                 masm.storeDouble(ScratchDoubleReg,
                                  Address(masm.getStackPointer(), iter->offsetFromArgBase()));
                 break;
               case MIRType::Float32:
                 masm.loadFloat32(src, ScratchFloat32Reg);
                 masm.storeFloat32(ScratchFloat32Reg,
@@ -323,17 +332,16 @@ wasm::GenerateEntry(MacroAssembler& masm
 }
 
 typedef bool ToValue;
 
 static void
 FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argOffset,
                   unsigned offsetToCallerStackArgs, Register scratch, ToValue toValue)
 {
-    Register64 scratch64(scratch);
     for (ABIArgValTypeIter i(args); !i.done(); i++) {
         Address dstAddr(masm.getStackPointer(), argOffset + i.index() * sizeof(Value));
 
         MIRType type = i.mirType();
         MOZ_ASSERT_IF(type == MIRType::Int64, JitOptions.wasmTestMode);
 
         switch (i->kind()) {
           case ABIArg::GPR:
@@ -393,18 +401,26 @@ FillArgumentArray(MacroAssembler& masm, 
                 else
                     masm.store32(scratch, dstAddr);
             } else if (type == MIRType::Int64) {
                 // We can't box int64 into Values (yet).
                 if (toValue) {
                     masm.breakpoint();
                 } else {
                     Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
+#if JS_BITS_PER_WORD == 32
+                    masm.load32(Address(src.base, src.offset + INT64LOW_OFFSET), scratch);
+                    masm.store32(scratch, Address(dstAddr.base, dstAddr.offset + INT64LOW_OFFSET));
+                    masm.load32(Address(src.base, src.offset + INT64HIGH_OFFSET), scratch);
+                    masm.store32(scratch, Address(dstAddr.base, dstAddr.offset + INT64HIGH_OFFSET));
+#else
+                    Register64 scratch64(scratch);
                     masm.load64(src, scratch64);
                     masm.store64(scratch64, dstAddr);
+#endif
                 }
             } else {
                 MOZ_ASSERT(IsFloatingPointType(type));
                 Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
                 if (toValue) {
                     if (type == MIRType::Float32) {
                         masm.loadFloat32(src, ScratchFloat32Reg);
                         masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -531,16 +531,24 @@ SuppressSignalHandlers(JSContext* cx, un
 
     wasm::SuppressSignalHandlersForTesting(ToBoolean(args[0]));
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
+WasmInt64IsSupported(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    args.rval().setBoolean(wasm::IsI64Implemented());
+    return true;
+}
+
+static bool
 WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject callee(cx, &args.callee());
 
     if (!args.requireAtLeast(cx, "wasmTextToBinary", 1))
         return false;
 
@@ -3848,16 +3856,20 @@ gc::ZealModeHelpText),
 "wasmUsesSignalForOOB()",
 "  Return whether wasm and asm.js use a signal handler for detecting out-of-bounds."),
 
     JS_FN_HELP("suppressSignalHandlers", SuppressSignalHandlers, 1, 0,
 "suppressSignalHandlers(suppress)",
 "  This function allows artificially suppressing signal handler support, even if the underlying "
 "  platform supports it."),
 
+    JS_FN_HELP("wasmInt64IsSupported", WasmInt64IsSupported, 0, 0,
+"wasmInt64IsSupported()",
+"  Returns a boolean indicating whether WebAssembly has 64bit integer support on the current device."),
+
     JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
 "wasmTextToBinary(str)",
 "  Translates the given text wasm module into its binary encoding."),
 
     JS_FN_HELP("wasmBinaryToText", WasmBinaryToText, 1, 0,
 "wasmBinaryToText(bin)",
 "  Translates binary encoding to text format"),
 
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -11,17 +11,17 @@ function wasmEvalText(str, imports) {
 }
 
 function mismatchError(actual, expect) {
     var str = `type mismatch: expression has type ${actual} but expected ${expect}`;
     return RegExp(str);
 }
 
 function hasI64() {
-    return getBuildConfiguration().x64;
+    return wasmInt64IsSupported();
 }
 
 function jsify(wasmVal) {
     if (wasmVal === 'nan')
         return NaN;
     if (wasmVal === 'infinity')
         return Infinity;
     if (wasmVal === '-infinity')