Bug 892634 - Part 2: Compile bit ops on values for parallel execution. (r=nmatsakis)
authorShu-yu Guo <shu@rfrn.org>
Fri, 02 Aug 2013 08:24:57 -0700
changeset 141147 4e12ba2df6a6cf16721c337217e2470dbe2d0745
parent 141146 56364871a2887fce84dcb44be001393e1a1f48c2
child 141148 699c21af878da8539a77b1b7b232e156c9d08bea
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersnmatsakis
bugs892634
milestone25.0a1
Bug 892634 - Part 2: Compile bit ops on values for parallel execution. (r=nmatsakis)
js/src/ion/CodeGenerator.cpp
js/src/ion/ParallelFunctions.cpp
js/src/ion/ParallelFunctions.h
js/src/ion/ParallelSafetyAnalysis.cpp
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -6130,31 +6130,45 @@ static const VMFunction ThrowInfo = Func
 bool
 CodeGenerator::visitThrow(LThrow *lir)
 {
     pushArg(ToValue(lir, LThrow::Value));
     return callVM(ThrowInfo, lir);
 }
 
 typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
-static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot);
+typedef ParallelResult (*BitNotParFn)(ForkJoinSlice *, HandleValue, int32_t *);
+static const VMFunctionsModal BitNotInfo = VMFunctionsModal(
+    FunctionInfo<BitNotFn>(BitNot),
+    FunctionInfo<BitNotParFn>(BitNotPar));
 
 bool
 CodeGenerator::visitBitNotV(LBitNotV *lir)
 {
     pushArg(ToValue(lir, LBitNotV::Input));
     return callVM(BitNotInfo, lir);
 }
 
 typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
-static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd);
-static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr);
-static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor);
-static const VMFunction BitLhsInfo = FunctionInfo<BitopFn>(BitLsh);
-static const VMFunction BitRhsInfo = FunctionInfo<BitopFn>(BitRsh);
+typedef ParallelResult (*BitopParFn)(ForkJoinSlice *, HandleValue, HandleValue, int32_t *);
+static const VMFunctionsModal BitAndInfo = VMFunctionsModal(
+    FunctionInfo<BitopFn>(BitAnd),
+    FunctionInfo<BitopParFn>(BitAndPar));
+static const VMFunctionsModal BitOrInfo = VMFunctionsModal(
+    FunctionInfo<BitopFn>(BitOr),
+    FunctionInfo<BitopParFn>(BitOrPar));
+static const VMFunctionsModal BitXorInfo = VMFunctionsModal(
+    FunctionInfo<BitopFn>(BitXor),
+    FunctionInfo<BitopParFn>(BitXorPar));
+static const VMFunctionsModal BitLhsInfo = VMFunctionsModal(
+    FunctionInfo<BitopFn>(BitLsh),
+    FunctionInfo<BitopParFn>(BitLshPar));
+static const VMFunctionsModal BitRhsInfo = VMFunctionsModal(
+    FunctionInfo<BitopFn>(BitRsh),
+    FunctionInfo<BitopParFn>(BitRshPar));
 
 bool
 CodeGenerator::visitBitOpV(LBitOpV *lir)
 {
     pushArg(ToValue(lir, LBitOpV::RhsInput));
     pushArg(ToValue(lir, LBitOpV::LhsInput));
 
     switch (lir->jsop()) {
--- a/js/src/ion/ParallelFunctions.cpp
+++ b/js/src/ion/ParallelFunctions.cpp
@@ -386,16 +386,89 @@ js::ion::StringsEqualPar(ForkJoinSlice *
 }
 
 ParallelResult
 js::ion::StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<false>(slice, v1, v2, res);
 }
 
+ParallelResult
+ion::BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out)
+{
+    if (in.isObject())
+        return TP_RETRY_SEQUENTIALLY;
+    int i;
+    if (!NonObjectToInt32(slice, in, &i))
+        return TP_FATAL;
+    *out = ~i;
+    return TP_SUCCESS;
+}
+
+#define BIT_OP(OP)                                                      \
+    JS_BEGIN_MACRO                                                      \
+    int32_t left, right;                                                \
+    if (lhs.isObject() || rhs.isObject())                               \
+        return TP_RETRY_SEQUENTIALLY;                                   \
+    if (!NonObjectToInt32(slice, lhs, &left) ||                         \
+        !NonObjectToInt32(slice, rhs, &right))                          \
+    {                                                                   \
+        return TP_FATAL;                                                \
+    }                                                                   \
+    *out = (OP);                                                        \
+    return TP_SUCCESS;                                                  \
+    JS_END_MACRO
+
+ParallelResult
+ion::BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
+{
+    BIT_OP(left ^ right);
+}
+
+ParallelResult
+ion::BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
+{
+    BIT_OP(left | right);
+}
+
+ParallelResult
+ion::BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
+{
+    BIT_OP(left & right);
+}
+
+ParallelResult
+ion::BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
+{
+    BIT_OP(left << (right & 31));
+}
+
+ParallelResult
+ion::BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
+{
+    BIT_OP(left >> (right & 31));
+}
+
+#undef BIT_OP
+
+ParallelResult
+ion::UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
+                   MutableHandleValue out)
+{
+    uint32_t left;
+    int32_t right;
+    if (lhs.isObject() || rhs.isObject())
+        return TP_RETRY_SEQUENTIALLY;
+    if (!NonObjectToUint32(slice, lhs, &left) || !NonObjectToInt32(slice, rhs, &right))
+        return TP_FATAL;
+    left >>= right & 31;
+    out.setNumber(uint32_t(left));
+    return TP_SUCCESS;
+}
+
 void
 ion::AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode)
 {
     // Spew before asserts to help with diagnosing failures.
     Spew(SpewBailouts,
          "Parallel abort with cause %d in %p:%s:%d "
          "(%p:%s:%d at line %d)",
--- a/js/src/ion/ParallelFunctions.h
+++ b/js/src/ion/ParallelFunctions.h
@@ -40,34 +40,46 @@ JSObject *ExtendArrayPar(ForkJoinSlice *
 
 // String related parallel functions. These tend to call existing VM functions
 // that take a ThreadSafeContext.
 ParallelResult ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
                                 MutableHandleString out);
 ParallelResult IntToStringPar(ForkJoinSlice *slice, int i, MutableHandleString out);
 ParallelResult DoubleToStringPar(ForkJoinSlice *slice, double d, MutableHandleString out);
 
-// These parallel operations fail if they would be required to convert
-// to a string etc etc.
+// Binary and unary operator functions on values. These tend to return
+// RETRY_SEQUENTIALLY if the values are objects.
 ParallelResult StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 ParallelResult GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 
 ParallelResult StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
 ParallelResult StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
 
+ParallelResult BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out);
+ParallelResult BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+ParallelResult BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+ParallelResult BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+ParallelResult BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+ParallelResult BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+
+ParallelResult UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
+                             MutableHandleValue out);
+
+// Make a new rest parameter in parallel.
 ParallelResult InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
                                     HandleObject templateObj, HandleObject res,
                                     MutableHandleObject out);
 
+// Abort and debug tracing functions.
 void AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode);
 void PropagateAbortPar(JSScript *outermostScript, JSScript *currentScript);
 
 void TraceLIR(uint32_t bblock, uint32_t lir, uint32_t execModeInt,
               const char *lirOpName, const char *mirOpName,
               JSScript *script, jsbytecode *pc);
 
--- a/js/src/ion/ParallelSafetyAnalysis.cpp
+++ b/js/src/ion/ParallelSafetyAnalysis.cpp
@@ -133,25 +133,25 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(PrepareCall)
     SAFE_OP(PassArg)
     CUSTOM_OP(Call)
     UNSAFE_OP(ApplyArgs)
     UNSAFE_OP(Bail)
     UNSAFE_OP(GetDynamicName)
     UNSAFE_OP(FilterArguments)
     UNSAFE_OP(CallDirectEval)
-    SPECIALIZED_OP(BitNot, PERMIT_INT32)
+    SAFE_OP(BitNot)
     UNSAFE_OP(TypeOf)
     SAFE_OP(ToId)
-    SPECIALIZED_OP(BitAnd, PERMIT_INT32)
-    SPECIALIZED_OP(BitOr, PERMIT_INT32)
-    SPECIALIZED_OP(BitXor, PERMIT_INT32)
-    SPECIALIZED_OP(Lsh, PERMIT_INT32)
-    SPECIALIZED_OP(Rsh, PERMIT_INT32)
-    SPECIALIZED_OP(Ursh, PERMIT_NUMERIC)
+    SAFE_OP(BitAnd)
+    SAFE_OP(BitOr)
+    SAFE_OP(BitXor)
+    SAFE_OP(Lsh)
+    SAFE_OP(Rsh)
+    SAFE_OP(Ursh)
     SPECIALIZED_OP(MinMax, PERMIT_NUMERIC)
     SAFE_OP(Abs)
     SAFE_OP(Sqrt)
     UNSAFE_OP(Atan2)
     SAFE_OP(MathFunction)
     SPECIALIZED_OP(Add, PERMIT_NUMERIC)
     SPECIALIZED_OP(Sub, PERMIT_NUMERIC)
     SPECIALIZED_OP(Mul, PERMIT_NUMERIC)