From 65d48642e266829c61f13108659dab72b0e1e4e0 Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Fri, 28 Feb 2014 23:48:07 +1300 Subject: [PATCH 01/62] Bug 957004 - Guard against object being lazily typed in IsPackedArray self-hosting intrinsic. r=jandem --HG-- extra : rebase_source : 824ff8327c37b430d600dd2fc070fac793f1cf1c --- js/src/jit-test/tests/self-hosting/bug957004.js | 3 +++ js/src/vm/SelfHosting.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/self-hosting/bug957004.js diff --git a/js/src/jit-test/tests/self-hosting/bug957004.js b/js/src/jit-test/tests/self-hosting/bug957004.js new file mode 100644 index 000000000000..ce767a9a4a3f --- /dev/null +++ b/js/src/jit-test/tests/self-hosting/bug957004.js @@ -0,0 +1,3 @@ +// No result, just mustn't crash. +Array.prototype.push(0); +Array.prototype.indexOf(); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 8870090cc0ad..738bf62c6947 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -482,7 +482,7 @@ js::intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp) JS_ASSERT(args[0].isObject()); JSObject *obj = &args[0].toObject(); - bool isPacked = obj->is() && + bool isPacked = obj->is() && !obj->hasLazyType() && !obj->type()->hasAllFlags(types::OBJECT_FLAG_NON_PACKED) && obj->getDenseInitializedLength() == obj->as().length(); From c63a4cffbff9328a86ad63b00c258e0fdf1d67f7 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 28 Feb 2014 12:07:05 +0100 Subject: [PATCH 02/62] Bug 930477: Specialize Round for Float32; r=jandem,mjrosenb --- .../tests/ion/testFloat32-correctness.js | 39 +++++++++ js/src/jit/CodeGenerator.cpp | 1 + js/src/jit/LIR-Common.h | 21 ++++- js/src/jit/LOpcodes.h | 1 + js/src/jit/Lowering.cpp | 13 ++- js/src/jit/MCallOptimize.cpp | 4 +- js/src/jit/MIR.cpp | 16 ++++ js/src/jit/MIR.h | 15 +++- js/src/jit/arm/CodeGenerator-arm.cpp | 15 ++++ js/src/jit/arm/CodeGenerator-arm.h | 1 + js/src/jit/arm/MacroAssembler-arm.cpp | 63 ++++++++++++++ js/src/jit/arm/MacroAssembler-arm.h | 1 + .../jit/shared/CodeGenerator-x86-shared.cpp | 87 +++++++++++++++++++ js/src/jit/shared/CodeGenerator-x86-shared.h | 1 + 14 files changed, 271 insertions(+), 7 deletions(-) diff --git a/js/src/jit-test/tests/ion/testFloat32-correctness.js b/js/src/jit-test/tests/ion/testFloat32-correctness.js index 1bb5d6b41a45..2c8b46963d38 100644 --- a/js/src/jit-test/tests/ion/testFloat32-correctness.js +++ b/js/src/jit-test/tests/ion/testFloat32-correctness.js @@ -230,6 +230,45 @@ function testFloorDouble() { test(setupFloor, testFloor); test(setupFloorDouble, testFloorDouble); +function setupRound() { + f32[0] = -5.5; + f32[1] = -0.6; + f32[2] = 1.5; + f32[3] = 1; +} +function setupRoundDouble() { + f32[4] = NaN; + f32[5] = -0.49; // rounded to -0 + f32[6] = Infinity; + f32[7] = -Infinity; + f32[8] = Math.pow(2,31); // too big to fit into a int + f32[9] = -0; +} +function testRound() { + for (var i = 0; i < 4; ++i) { + var r32 = Math.round(f32[i]); + assertFloat32(r32, false); // r32 is an int32 + + var r64 = Math.round(-0 + f32[i]); + assertFloat32(r64, false); + + assertEq(r32, r64); + } +} +function testRoundDouble() { + for (var i = 4; i < 10; ++i) { + var r32 = Math.fround(Math.round(f32[i])); + assertFloat32(r32, true); + + var r64 = Math.round(-0 + f32[i]); + assertFloat32(r64, false); + + assertEq(r32, r64); + } +} +test(setupRound, testRound); +test(setupRoundDouble, testRoundDouble); + function setupCeil() { f32[0] = -5.5; f32[1] = -1.5; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index de2445bc4360..192fa749609e 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -4306,6 +4306,7 @@ CodeGenerator::visitMathFunctionF(LMathFunctionF *ins) void *funptr = nullptr; switch (ins->mir()->function()) { case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void *, floorf); break; + case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void *, roundf); break; case MMathFunction::Ceil: funptr = JS_FUNC_TO_DATA_PTR(void *, ceilf); break; default: MOZ_ASSUME_UNREACHABLE("Unknown or unsupported float32 math function"); diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index c15582fe556b..44a1ad7ade62 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -4738,7 +4738,7 @@ class LFloorF : public LInstructionHelper<1, 1, 0> } }; -// Round a number. Implements Math.round(). +// Round a double precision number. Implements Math.round(). class LRound : public LInstructionHelper<1, 1, 1> { public: @@ -4757,6 +4757,25 @@ class LRound : public LInstructionHelper<1, 1, 1> } }; +// Round a single precision number. Implements Math.round(). +class LRoundF : public LInstructionHelper<1, 1, 1> +{ + public: + LIR_HEADER(RoundF) + + LRoundF(const LAllocation &num, const LDefinition &temp) { + setOperand(0, num); + setTemp(0, temp); + } + + const LDefinition *temp() { + return getTemp(0); + } + MRound *mir() const { + return mir_->toRound(); + } +}; + // Load a function's call environment. class LFunctionEnvironment : public LInstructionHelper<1, 1, 0> { diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index b83fa7901669..d5fa461b0ef0 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -261,6 +261,7 @@ _(Floor) \ _(FloorF) \ _(Round) \ + _(RoundF) \ _(In) \ _(InArray) \ _(InstanceOfO) \ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index bb17e1a49ba4..f6e5ba026f2c 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -1179,8 +1179,17 @@ LIRGenerator::visitFloor(MFloor *ins) bool LIRGenerator::visitRound(MRound *ins) { - JS_ASSERT(ins->num()->type() == MIRType_Double); - LRound *lir = new(alloc()) LRound(useRegister(ins->num()), tempDouble()); + MIRType type = ins->num()->type(); + JS_ASSERT(IsFloatingPointType(type)); + + if (type == MIRType_Double) { + LRound *lir = new (alloc()) LRound(useRegister(ins->num()), tempDouble()); + if (!assignSnapshot(lir)) + return false; + return define(lir, ins); + } + + LRoundF *lir = new (alloc()) LRoundF(useRegister(ins->num()), tempDouble()); if (!assignSnapshot(lir)) return false; return define(lir, ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 9b00fd1240db..bbb14a84213c 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -673,7 +673,7 @@ IonBuilder::inlineMathRound(CallInfo &callInfo) return InliningStatus_Inlined; } - if (argType == MIRType_Double && returnType == MIRType_Int32) { + if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { callInfo.setImplicitlyUsedUnchecked(); MRound *ins = MRound::New(alloc(), callInfo.getArg(0)); current->add(ins); @@ -681,7 +681,7 @@ IonBuilder::inlineMathRound(CallInfo &callInfo) return InliningStatus_Inlined; } - if (argType == MIRType_Double && returnType == MIRType_Double) { + if (IsFloatingPointType(argType) && returnType == MIRType_Double) { callInfo.setImplicitlyUsedUnchecked(); MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round, nullptr); current->add(ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 2b4233749548..0ce5be004635 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -810,6 +810,22 @@ MFloor::trySpecializeFloat32(TempAllocator &alloc) setPolicyType(MIRType_Float32); } +void +MRound::trySpecializeFloat32(TempAllocator &alloc) +{ + // No need to look at the output, as it's an integer (unique way to have + // this instruction in IonBuilder::inlineMathRound) + JS_ASSERT(type() == MIRType_Int32); + + if (!input()->canProduceFloat32()) { + if (input()->type() == MIRType_Float32) + ConvertDefinitionToDouble<0>(alloc, input(), this); + return; + } + + setPolicyType(MIRType_Float32); +} + MTest * MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 4c4f2d992ec5..6695a4e09995 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3930,7 +3930,7 @@ class MMathFunction static const char *FunctionName(Function function); bool isFloat32Commutative() const { - return function_ == Floor || function_ == Ceil; + return function_ == Floor || function_ == Ceil || function_ == Round; } void trySpecializeFloat32(TempAllocator &alloc); void computeRange(TempAllocator &alloc); @@ -8283,12 +8283,13 @@ class MFloor // Inlined version of Math.round(). class MRound : public MUnaryInstruction, - public DoublePolicy<0> + public FloatingPointPolicy<0> { MRound(MDefinition *num) : MUnaryInstruction(num) { setResultType(MIRType_Int32); + setPolicyType(MIRType_Double); setMovable(); } @@ -8308,6 +8309,16 @@ class MRound TypePolicy *typePolicy() { return this; } + + bool isFloat32Commutative() const { + return true; + } + void trySpecializeFloat32(TempAllocator &alloc); +#ifdef DEBUG + bool isConsistentFloat32Use(MUse *use) const { + return true; + } +#endif }; class MIteratorStart diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index a2588920487a..b850916f88e8 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -1244,6 +1244,21 @@ CodeGeneratorARM::visitRound(LRound *lir) return true; } +bool +CodeGeneratorARM::visitRoundF(LRoundF *lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + Register output = ToRegister(lir->output()); + FloatRegister tmp = ToFloatRegister(lir->temp()); + Label bail; + // Output is either correct, or clamped. All -0 cases have been translated to a clamped + // case.a + masm.roundf(input, output, &bail, tmp); + if (!bailoutFrom(&bail, lir->snapshot())) + return false; + return true; +} + void CodeGeneratorARM::emitRoundDouble(const FloatRegister &src, const Register &dest, Label *fail) { diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index 120c1b058c54..94df6d7dee51 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -112,6 +112,7 @@ class CodeGeneratorARM : public CodeGeneratorShared virtual bool visitFloor(LFloor *lir); virtual bool visitFloorF(LFloorF *lir); virtual bool visitRound(LRound *lir); + virtual bool visitRoundF(LRoundF *lir); virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins); virtual bool visitTruncateFToInt32(LTruncateFToInt32 *ins); diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 6c2721ea44ed..1cff932432fb 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4144,6 +4144,69 @@ MacroAssemblerARMCompat::round(FloatRegister input, Register output, Label *bail bind(&fin); } +void +MacroAssemblerARMCompat::roundf(FloatRegister input, Register output, Label *bail, FloatRegister tmp) +{ + Label handleZero; + Label handleNeg; + Label fin; + // Do a compare based on the original value, then do most other things based on the + // shifted value. + ma_vcmpz_f32(input); + // Adding 0.5 is technically incorrect! + // We want to add 0.5 to negative numbers, and 0.49999999999999999 to positive numbers. + ma_vimm_f32(0.5f, ScratchFloatReg); + // Since we already know the sign bit, flip all numbers to be positive, stored in tmp. + ma_vabs_f32(input, tmp); + // Add 0.5, storing the result into tmp. + ma_vadd_f32(ScratchFloatReg, tmp, tmp); + as_vmrs(pc); + ma_b(&handleZero, Assembler::Equal); + ma_b(&handleNeg, Assembler::Signed); + // NaN is always a bail condition, just bail directly. + ma_b(bail, Assembler::Overflow); + + // The argument is a positive number, truncation is the path to glory; + // Since it is known to be > 0.0, explicitly convert to a larger range, + // then a value that rounds to INT_MAX is explicitly different from an + // argument that clamps to INT_MAX + ma_vcvt_F32_U32(tmp, ScratchFloatReg); + ma_vxfer(VFPRegister(ScratchFloatReg).uintOverlay(), output); + ma_mov(output, output, SetCond); + ma_b(bail, Signed); + ma_b(&fin); + + bind(&handleZero); + // Move the top word of the double into the output reg, if it is non-zero, + // then the original value was -0.0 + as_vxfer(output, InvalidReg, input, FloatToCore, Always, 1); + ma_cmp(output, Imm32(0)); + ma_b(bail, NonZero); + ma_b(&fin); + + bind(&handleNeg); + // Negative case, negate, then start dancing. This number may be positive, since we added 0.5 + ma_vcvt_F32_U32(tmp, ScratchFloatReg); + ma_vxfer(VFPRegister(ScratchFloatReg).uintOverlay(), output); + + // -output is now a correctly rounded value, unless the original value was exactly + // halfway between two integers, at which point, it has been rounded away from zero, when + // it should be rounded towards \infty. + ma_vcvt_U32_F32(ScratchFloatReg, ScratchFloatReg); + compareFloat(ScratchFloatReg, tmp); + ma_sub(output, Imm32(1), output, NoSetCond, Equal); + // Negate the output. Since INT_MIN < -INT_MAX, even after adding 1, + // the result will still be a negative number + ma_rsb(output, Imm32(0), output, SetCond); + + // If the result looks non-negative, then this value didn't actually fit into + // the int range, and special handling is required, or it was zero, which means + // the result is actually -0.0 which also requires special handling. + ma_b(bail, NotSigned); + + bind(&fin); +} + CodeOffsetJump MacroAssemblerARMCompat::jumpWithPatch(RepatchLabel *label, Condition cond) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 89757cfba659..5d6d18b62229 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1441,6 +1441,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void floor(FloatRegister input, Register output, Label *handleNotAnInt); void floorf(FloatRegister input, Register output, Label *handleNotAnInt); void round(FloatRegister input, Register output, Label *handleNotAnInt, FloatRegister tmp); + void roundf(FloatRegister input, Register output, Label *handleNotAnInt, FloatRegister tmp); void clampCheck(Register r, Label *handleNotAnInt) { // check explicitly for r == INT_MIN || r == INT_MAX diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index a98ba585ab47..d4cd0fb97876 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -1666,6 +1666,93 @@ CodeGeneratorX86Shared::visitRound(LRound *lir) return true; } +bool +CodeGeneratorX86Shared::visitRoundF(LRoundF *lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister temp = ToFloatRegister(lir->temp()); + FloatRegister scratch = ScratchFloatReg; + Register output = ToRegister(lir->output()); + + Label negative, end; + + // Load 0.5 in the temp register. + masm.loadConstantFloat32(0.5f, temp); + + // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. + masm.xorps(scratch, scratch); + masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &negative); + + // Bail on negative-zero. + Assembler::Condition bailCond = masm.testNegativeZeroFloat32(input, output); + if (!bailoutIf(bailCond, lir->snapshot())) + return false; + + // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we + // have to add the input to the temp register (which contains 0.5) because + // we're not allowed to modify the input register. + masm.addss(input, temp); + + masm.cvttss2si(temp, output); + masm.cmp32(output, Imm32(INT_MIN)); + if (!bailoutIf(Assembler::Equal, lir->snapshot())) + return false; + + masm.jump(&end); + + + // Input is negative, but isn't -0. + masm.bind(&negative); + + if (AssemblerX86Shared::HasSSE41()) { + // Add 0.5 and round toward -Infinity. The result is stored in the temp + // register (currently contains 0.5). + masm.addss(input, temp); + masm.roundss(temp, scratch, JSC::X86Assembler::RoundDown); + + // Truncate. + masm.cvttss2si(scratch, output); + masm.cmp32(output, Imm32(INT_MIN)); + if (!bailoutIf(Assembler::Equal, lir->snapshot())) + return false; + + // If the result is positive zero, then the actual result is -0. Bail. + // Otherwise, the truncation will have produced the correct negative integer. + masm.testl(output, output); + if (!bailoutIf(Assembler::Zero, lir->snapshot())) + return false; + + } else { + masm.addss(input, temp); + // Round toward -Infinity without the benefit of ROUNDSS. + { + // If input + 0.5 >= 0, input is a negative number >= -0.5 and the result is -0. + masm.compareFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch); + if (!bailoutIf(Assembler::DoubleGreaterThanOrEqual, lir->snapshot())) + return false; + + // Truncate and round toward zero. + // This is off-by-one for everything but integer-valued inputs. + masm.cvttss2si(temp, output); + masm.cmp32(output, Imm32(INT_MIN)); + if (!bailoutIf(Assembler::Equal, lir->snapshot())) + return false; + + // Test whether the truncated double was integer-valued. + masm.convertInt32ToFloat32(output, scratch); + masm.branchFloat(Assembler::DoubleEqualOrUnordered, temp, scratch, &end); + + // Input is not integer-valued, so we rounded off-by-one in the + // wrong direction. Correct by subtraction. + masm.subl(Imm32(1), output); + // Cannot overflow: output was already checked against INT_MIN. + } + } + + masm.bind(&end); + return true; +} + bool CodeGeneratorX86Shared::visitGuardShape(LGuardShape *guard) { diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.h b/js/src/jit/shared/CodeGenerator-x86-shared.h index 1ad0ae07d160..8d706772d7d7 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/shared/CodeGenerator-x86-shared.h @@ -115,6 +115,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared virtual bool visitFloor(LFloor *lir); virtual bool visitFloorF(LFloorF *lir); virtual bool visitRound(LRound *lir); + virtual bool visitRoundF(LRoundF *lir); virtual bool visitGuardShape(LGuardShape *guard); virtual bool visitGuardObjectType(LGuardObjectType *guard); virtual bool visitGuardClass(LGuardClass *guard); From c2e266f0f0b0cf3369aa47897def3b11fe6d5ef3 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 28 Feb 2014 12:07:40 +0100 Subject: [PATCH 03/62] Bug 930477: Implemented roundf for all platforms; r=waldo --- js/src/jit/CodeGenerator.cpp | 6 +++--- js/src/jsmath.cpp | 24 +++++++++++++++++++----- js/src/jsmath.h | 3 +++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 192fa749609e..19e18f3cf43b 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -4305,9 +4305,9 @@ CodeGenerator::visitMathFunctionF(LMathFunctionF *ins) void *funptr = nullptr; switch (ins->mir()->function()) { - case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void *, floorf); break; - case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void *, roundf); break; - case MMathFunction::Ceil: funptr = JS_FUNC_TO_DATA_PTR(void *, ceilf); break; + case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void *, floorf); break; + case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void *, math_roundf_impl); break; + case MMathFunction::Ceil: funptr = JS_FUNC_TO_DATA_PTR(void *, ceilf); break; default: MOZ_ASSUME_UNREACHABLE("Unknown or unsupported float32 math function"); } diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 629fa5a58228..3751fed2c42f 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -38,6 +38,7 @@ using mozilla::Abs; using mozilla::NumberEqualsInt32; using mozilla::NumberIsInt32; using mozilla::ExponentComponent; +using mozilla::FloatingPoint; using mozilla::IsFinite; using mozilla::IsInfinite; using mozilla::IsNaN; @@ -45,7 +46,6 @@ using mozilla::IsNegative; using mozilla::IsNegativeZero; using mozilla::PositiveInfinity; using mozilla::NegativeInfinity; -using mozilla::SpecificNaN; using JS::ToNumber; using JS::GenericNaN; @@ -745,17 +745,31 @@ js_math_random(JSContext *cx, unsigned argc, Value *vp) double js::math_round_impl(double x) { - int32_t i; - if (NumberIsInt32(x, &i)) - return double(i); + int32_t ignored; + if (NumberIsInt32(x, &ignored)) + return x; /* Some numbers are so big that adding 0.5 would give the wrong number. */ - if (ExponentComponent(x) >= 52) + if (ExponentComponent(x) >= int_fast16_t(FloatingPoint::ExponentShift)) return x; return js_copysign(floor(x + 0.5), x); } +float +js::math_roundf_impl(float x) +{ + int32_t ignored; + if (NumberIsInt32(x, &ignored)) + return x; + + /* Some numbers are so big that adding 0.5 would give the wrong number. */ + if (ExponentComponent(x) >= int_fast16_t(FloatingPoint::ExponentShift)) + return x; + + return js_copysign(floorf(x + 0.5f), x); +} + bool /* ES5 15.8.2.15. */ js::math_round(JSContext *cx, unsigned argc, Value *vp) { diff --git a/js/src/jsmath.h b/js/src/jsmath.h index 910a80c35ec9..d10f0ed29ab7 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -265,6 +265,9 @@ math_round(JSContext *cx, unsigned argc, Value *vp); extern double math_round_impl(double x); +extern float +math_roundf_impl(float x); + extern double powi(double x, int y); From cb16191dfc02d141a0cde6d153370d4a852f2bd8 Mon Sep 17 00:00:00 2001 From: Frank Wein Date: Fri, 28 Feb 2014 12:32:14 +0100 Subject: [PATCH 04/62] =?UTF-8?q?Bug=20977667=20-=20VolatileBufferFallback?= =?UTF-8?q?.cpp:16:10:=20error:=20=C3=A2=E2=82=AC=CB=9Cnullptr=C3=A2?= =?UTF-8?q?=E2=82=AC=E2=84=A2=20was=20not=20declared=20in=20this=20scope,?= =?UTF-8?q?=20r=3Dglandium?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memory/mozalloc/VolatileBufferFallback.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/memory/mozalloc/VolatileBufferFallback.cpp b/memory/mozalloc/VolatileBufferFallback.cpp index 9445b6067399..bcc3045af1bb 100644 --- a/memory/mozalloc/VolatileBufferFallback.cpp +++ b/memory/mozalloc/VolatileBufferFallback.cpp @@ -4,6 +4,7 @@ #include "VolatileBuffer.h" #include "mozilla/Assertions.h" +#include "mozilla/NullPtr.h" #include "mozilla/mozalloc.h" #ifdef MOZ_MEMORY From fd055a66f1897e4f4132fe9c41a4802b23cefd26 Mon Sep 17 00:00:00 2001 From: "Nicholas D. Matsakis" Date: Fri, 28 Feb 2014 06:44:06 -0500 Subject: [PATCH 05/62] Bug 978047 -- check for OOM r=h4writer --- js/src/builtin/TypedObject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index cf87ccf244d6..e9f98d96aec6 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -894,8 +894,12 @@ StructMetaTypeDescr::layout(JSContext *cx, // fieldTypes : { string: Type, ... } RootedObject fieldOffsets(cx); fieldOffsets = NewObjectWithProto(cx, nullptr, nullptr, TenuredObject); + if (!fieldOffsets) + return false; RootedObject fieldTypes(cx); fieldTypes = NewObjectWithProto(cx, nullptr, nullptr, TenuredObject); + if (!fieldTypes) + return false; for (size_t i = 0; i < typeRepr->fieldCount(); i++) { const StructField &field = typeRepr->field(i); RootedId fieldId(cx, NameToId(field.propertyName)); From 95a47b6810ebdcc91dfa987546e1907b49060132 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 28 Feb 2014 08:17:22 -0500 Subject: [PATCH 06/62] Bug 976898 - Move the sdkdecls.h force-include out of the build system; r=bbondy,glandium --- mozilla-config.h.in | 10 ++++++++++ security/sandbox/Makefile.in | 8 -------- security/sandbox/moz.build | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mozilla-config.h.in b/mozilla-config.h.in index 3dfcd3c1ef3f..6212581f5171 100644 --- a/mozilla-config.h.in +++ b/mozilla-config.h.in @@ -50,5 +50,15 @@ #include "hunspell_fopen_hooks.h" #endif +/* + * Force-include sdkdecls.h for building the chromium sandbox code. + * + * CHROMIUM_SANDBOX_BUILD is defined in security/sandbox/moz.build. + * Note that this include path relies on the LOCAL_INCLUDES in that file. + */ +#if defined(CHROMIUM_SANDBOX_BUILD) && defined(XP_WIN) +#include "base/shim/sdkdecls.h" +#endif + #endif /* _MOZILLA_CONFIG_H_ */ diff --git a/security/sandbox/Makefile.in b/security/sandbox/Makefile.in index 5bbdb529ff39..67133c4cd6ae 100644 --- a/security/sandbox/Makefile.in +++ b/security/sandbox/Makefile.in @@ -3,14 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. ifeq ($(OS_ARCH),WINNT) -EXTRA_SDK_DECLS = $(topsrcdir)/security/sandbox/chromium/base/shim/sdkdecls.h - -ifdef _MSC_VER -OS_CXXFLAGS += -FI $(EXTRA_SDK_DECLS) -else -OS_CXXFLAGS += -include $(EXTRA_SDK_DECLS) -endif - STL_FLAGS = MOZ_GLUE_LDFLAGS = endif diff --git a/security/sandbox/moz.build b/security/sandbox/moz.build index c1cdf92fa6aa..40c2502892fd 100644 --- a/security/sandbox/moz.build +++ b/security/sandbox/moz.build @@ -121,7 +121,7 @@ elif CONFIG['OS_ARCH'] == 'WINNT': ] for var in ('UNICODE', '_UNICODE', 'NS_NO_XPCOM', 'SANDBOX_EXPORTS', - 'NOMINMAX', '_CRT_RAND_S'): + 'NOMINMAX', '_CRT_RAND_S', 'CHROMIUM_SANDBOX_BUILD'): DEFINES[var] = True LOCAL_INCLUDES += ['/security/sandbox/chromium/base/shim'] From e69879d6bd98f7edc4958830e2e7332cfee3dd83 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 28 Feb 2014 08:57:13 -0500 Subject: [PATCH 07/62] Bug 977950. Fix dragging of text to work again. r=smaug --- dom/events/DataTransfer.cpp | 2 +- dom/events/DragEvent.cpp | 1 - dom/events/nsEventStateManager.cpp | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 994ca198e5e0..30a8fa4ec12a 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -320,7 +320,7 @@ NS_IMETHODIMP DataTransfer::GetFiles(nsIDOMFileList** aFileList) { ErrorResult rv; - *aFileList = GetFiles(rv); + NS_IF_ADDREF(*aFileList = GetFiles(rv)); return rv.ErrorCode(); } diff --git a/dom/events/DragEvent.cpp b/dom/events/DragEvent.cpp index 3dbcf9a3182f..a099fdc9d8f3 100644 --- a/dom/events/DragEvent.cpp +++ b/dom/events/DragEvent.cpp @@ -87,7 +87,6 @@ DragEvent::InitDragEvent(const nsAString& aType, nsIDOMDataTransfer* aDataTransfer) { nsCOMPtr dataTransfer = do_QueryInterface(aDataTransfer); - NS_ENSURE_ARG(dataTransfer); nsresult rv = MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail, diff --git a/dom/events/nsEventStateManager.cpp b/dom/events/nsEventStateManager.cpp index d8b2d8b990c1..fc116141a51a 100644 --- a/dom/events/nsEventStateManager.cpp +++ b/dom/events/nsEventStateManager.cpp @@ -2337,9 +2337,9 @@ nsEventStateManager::DoDefaultDragStart(nsPresContext* aPresContext, // target of the mouse event. If one wasn't set in the // aDataTransfer during the event handler, just use the original // target instead. - nsCOMPtr dragTarget = aDataTransfer->GetDragTarget(); + nsCOMPtr dragTarget = aDataTransfer->GetDragTarget(); if (!dragTarget) { - dragTarget = do_QueryInterface(aDragTarget); + dragTarget = aDragTarget; if (!dragTarget) return false; } From 86168712ad56a96df594eaf97481e49aa3c2f03a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 14 Feb 2014 10:46:09 -0500 Subject: [PATCH 08/62] Bug 952890 part 1. Make WebIDL sequence JS to C++ conversions use for-of iteration, not length/index gets. r=peterv --- dom/bindings/Codegen.py | 43 +++++++++---------- dom/contacts/tests/test_contacts_basics2.html | 9 ++-- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 264b18a38751..5ec31acc1006 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -3105,31 +3105,35 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, arrayRef = "${declName}" # NOTE: Keep this in sync with variadic conversions as needed - templateBody = ("""JS::Rooted seq(cx, &${val}.toObject());\n -if (!IsArrayLike(cx, seq)) { + templateBody = ("""JS::ForOfIterator iter(cx); +if (!iter.init(${val}, JS::ForOfIterator::AllowNonIterable)) { %s } -uint32_t length; -// JS_GetArrayLength actually works on all objects -if (!JS_GetArrayLength(cx, seq, &length)) { +if (!iter.valueIsIterable()) { %s } %s &arr = %s; -if (!arr.SetCapacity(length)) { - JS_ReportOutOfMemory(cx); -%s -} -for (uint32_t i = 0; i < length; ++i) { - JS::Rooted temp(cx); - if (!JS_GetElement(cx, seq, i, &temp)) { +JS::Rooted temp(cx); +while (true) { + bool done; + if (!iter.next(&temp, &done)) { %s } - %s& slot = *arr.AppendElement(); -""" % (CGIndenter(CGGeneric(notSequence)).define(), - exceptionCodeIndented.define(), + if (done) { + break; + } + %s* slotPtr = arr.AppendElement(); + if (!slotPtr) { + JS_ReportOutOfMemory(cx); +%s + } + %s& slot = *slotPtr; +""" % (exceptionCodeIndented.define(), + CGIndenter(CGGeneric(notSequence)).define(), sequenceType, arrayRef, - exceptionCodeIndented.define(), + CGIndenter(exceptionCodeIndented).define(), + elementInfo.declType.define(), CGIndenter(exceptionCodeIndented).define(), elementInfo.declType.define())) @@ -3196,12 +3200,7 @@ for (uint32_t i = 0; i < length; ++i) { arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes) if len(arrayObjectMemberTypes) > 0: - assert len(arrayObjectMemberTypes) == 1 - memberType = arrayObjectMemberTypes[0] - name = memberType.name - arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;" % (unionArgumentObj, name)) - arrayObject = CGIfWrapper(arrayObject, "IsArrayLike(cx, argObj)") - names.append(name) + raise TypeError("Bug 767924: We don't support sequences in unions yet") else: arrayObject = None diff --git a/dom/contacts/tests/test_contacts_basics2.html b/dom/contacts/tests/test_contacts_basics2.html index 43353cb2c1c4..bf8d7b5bf11e 100644 --- a/dom/contacts/tests/test_contacts_basics2.html +++ b/dom/contacts/tests/test_contacts_basics2.html @@ -681,12 +681,15 @@ var steps = [ req.onerror = onFailure; }, function() { - ok(true, "Test setting array properties to scalar values") + ok(true, "Test that after setting array properties to scalar values the property os not a non-array") const FIELDS = ["email","url","adr","tel","impp"]; createResult1 = new mozContact(); for (var prop of FIELDS) { - createResult1[prop] = {type: ["foo"]}; - ok(Array.isArray(createResult1[prop]), prop + " is array"); + try { + createResult1[prop] = {type: ["foo"]}; + } catch (e) {} + ok(createResult1[prop] === null || + Array.isArray(createResult1[prop]), prop + " is array"); } next(); }, From 6519b1495e77988487ac5a3ccd543b53c4f4aca1 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 14 Feb 2014 10:46:09 -0500 Subject: [PATCH 09/62] Bug 952890 part 2. Remove the IsArrayLike method, since it no longer matches any spec concept. r=peterv --- dom/base/nsScreen.cpp | 65 ---------------------------- dom/bindings/BindingUtils.h | 6 --- dom/interfaces/base/nsIDOMScreen.idl | 34 +-------------- 3 files changed, 1 insertion(+), 104 deletions(-) diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp index 23d7e3593cc7..9c634dee32fa 100644 --- a/dom/base/nsScreen.cpp +++ b/dom/base/nsScreen.cpp @@ -222,64 +222,6 @@ nsScreen::GetLockOrientationPermission() const return doc->MozFullScreen() ? FULLSCREEN_LOCK_ALLOWED : LOCK_DENIED; } -NS_IMETHODIMP -nsScreen::MozLockOrientation(JS::Handle aOrientation, JSContext* aCx, - bool* aReturn) -{ - if (aOrientation.isObject()) { - JS::Rooted seq(aCx, &aOrientation.toObject()); - if (IsArrayLike(aCx, seq)) { - uint32_t length; - // JS_GetArrayLength actually works on all objects - if (!JS_GetArrayLength(aCx, seq, &length)) { - return NS_ERROR_FAILURE; - } - - Sequence orientations; - if (!orientations.SetCapacity(length)) { - return NS_ERROR_OUT_OF_MEMORY; - } - - for (uint32_t i = 0; i < length; ++i) { - JS::Rooted temp(aCx); - if (!JS_GetElement(aCx, seq, i, &temp)) { - return NS_ERROR_FAILURE; - } - - JS::Rooted jsString(aCx, JS::ToString(aCx, temp)); - if (!jsString) { - return NS_ERROR_FAILURE; - } - - nsDependentJSString str; - if (!str.init(aCx, jsString)) { - return NS_ERROR_FAILURE; - } - - *orientations.AppendElement() = str; - } - - ErrorResult rv; - *aReturn = MozLockOrientation(orientations, rv); - return rv.ErrorCode(); - } - } - - JS::Rooted jsString(aCx, JS::ToString(aCx, aOrientation)); - if (!jsString) { - return NS_ERROR_FAILURE; - } - - nsDependentJSString orientation; - if (!orientation.init(aCx, jsString)) { - return NS_ERROR_FAILURE; - } - - ErrorResult rv; - *aReturn = MozLockOrientation(orientation, rv); - return rv.ErrorCode(); -} - bool nsScreen::MozLockOrientation(const nsAString& aOrientation, ErrorResult& aRv) { @@ -365,13 +307,6 @@ nsScreen::MozUnlockOrientation() hal::UnlockScreenOrientation(); } -NS_IMETHODIMP -nsScreen::SlowMozUnlockOrientation() -{ - MozUnlockOrientation(); - return NS_OK; -} - bool nsScreen::IsDeviceSizePageSize() { diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 5823f7aad8bc..c3c549e0f66c 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -263,12 +263,6 @@ IsNotDateOrRegExp(JSContext* cx, JS::Handle obj) return !JS_ObjectIsDate(cx, obj) && !JS_ObjectIsRegExp(cx, obj); } -MOZ_ALWAYS_INLINE bool -IsArrayLike(JSContext* cx, JS::Handle obj) -{ - return IsNotDateOrRegExp(cx, obj); -} - MOZ_ALWAYS_INLINE bool IsObjectValueConvertibleToDictionary(JSContext* cx, JS::Handle objVal) diff --git a/dom/interfaces/base/nsIDOMScreen.idl b/dom/interfaces/base/nsIDOMScreen.idl index 111c1954920f..cc53cf90b1a0 100644 --- a/dom/interfaces/base/nsIDOMScreen.idl +++ b/dom/interfaces/base/nsIDOMScreen.idl @@ -5,7 +5,7 @@ #include "nsIDOMEventTarget.idl" -[scriptable, builtinclass, uuid(bcdf4ce4-9785-4e31-a851-1d51ea16da20)] +[scriptable, builtinclass, uuid(e732649a-4f78-4ded-abe1-dbdc36fd59d3)] interface nsIDOMScreen : nsIDOMEventTarget { readonly attribute long top; @@ -26,36 +26,4 @@ interface nsIDOMScreen : nsIDOMEventTarget */ [binaryname(SlowMozOrientation)] readonly attribute DOMString mozOrientation; - - /** - * Lock the screen to the specified orientations(s). This method returns true - * if the lock was acquired successfully, and false otherwise. - * - * The parameter can be a DOMString or an Array of DOMStrings. If you pass a - * string, we lock the screen to that one orientation. If you pass an Array, - * we ensure that the screen is always in one of the given orientations. - * - * Valid orientations are "portrait", "portrait-primary", - * "portrait-secondary", "landscape", "landscape-primary", and - * "landscape-secondary". - * These tokens are case-sensitive. - * - * If you pass a string that's not one of the valid orientations, or if you - * pass an array of orientations and any of the orientations in the array is - * not valid, we reject the lock and return false. - * - * The "-primary" orientations correspond to holding the device right-side up, - * while the "-secondary" orientations correspond to holding the device - * upside-down. Locking the orientation in "portrait" is the same as locking - * the orientation in ['portrait-primary', 'portrait-secondary'], and the - * "landscape" orientation similarly corresponds to the set - * ['landscape-primary', 'landscape-secondary']. - */ - [implicit_jscontext] boolean mozLockOrientation(in jsval orientation); - - /** - * Unlock the screen orientation. - */ - [binaryname(SlowMozUnlockOrientation)] - void mozUnlockOrientation(); }; From 4fd9fff1128c2f3b040f9e916334835bd581bc23 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Fri, 28 Feb 2014 07:37:30 -0600 Subject: [PATCH 10/62] Bug 969831 - Share code for checking minumum d3d feature level required for running metro and expose this information (including cached check results) via nsIWinMetroUtils. r=bbondy --- .../shell/commandexecutehandler/CEHHelper.cpp | 71 +------------- .../shell/commandexecutehandler/CEHHelper.h | 4 - .../CommandExecuteHandler.cpp | 5 + widget/nsIWinMetroUtils.idl | 10 +- widget/windows/winrt/MetroD3DCheckHelper.h | 96 +++++++++++++++++++ widget/windows/winrt/moz.build | 4 + widget/windows/winrt/nsWinMetroUtils.cpp | 57 +++++++++++ 7 files changed, 174 insertions(+), 73 deletions(-) create mode 100644 widget/windows/winrt/MetroD3DCheckHelper.h diff --git a/browser/metro/shell/commandexecutehandler/CEHHelper.cpp b/browser/metro/shell/commandexecutehandler/CEHHelper.cpp index ab279bf394c6..35ec10871165 100644 --- a/browser/metro/shell/commandexecutehandler/CEHHelper.cpp +++ b/browser/metro/shell/commandexecutehandler/CEHHelper.cpp @@ -5,6 +5,7 @@ #include "CEHHelper.h" #include +#include "mozilla/widget/MetroD3DCheckHelper.h" #ifdef SHOW_CONSOLE #include // _open_osfhandle @@ -139,73 +140,9 @@ IsDX10Available() if (GetDWORDRegKey(metroDX10Available, isDX10Available)) { return isDX10Available; } - - HMODULE dxgiModule = LoadLibraryA("dxgi.dll"); - if (!dxgiModule) { - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - decltype(CreateDXGIFactory1)* createDXGIFactory1 = - (decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, "CreateDXGIFactory1"); - if (!createDXGIFactory1) { - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - - HMODULE d3d10module = LoadLibraryA("d3d10_1.dll"); - if (!d3d10module) { - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - decltype(D3D10CreateDevice1)* createD3DDevice = - (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, - "D3D10CreateDevice1"); - if (!createD3DDevice) { - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - - CComPtr factory1; - if (FAILED(createDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory1))) { - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - - CComPtr adapter1; - if (FAILED(factory1->EnumAdapters1(0, &adapter1))) { - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - - CComPtr device; - // Try for DX10.1 - if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, - D3D10_CREATE_DEVICE_BGRA_SUPPORT | - D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, - D3D10_FEATURE_LEVEL_10_1, - D3D10_1_SDK_VERSION, &device))) { - // Try for DX10 - if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, - D3D10_CREATE_DEVICE_BGRA_SUPPORT | - D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, - D3D10_FEATURE_LEVEL_10_0, - D3D10_1_SDK_VERSION, &device))) { - // Try for DX9.3 (we fall back to cairo and cairo has support for D3D 9.3) - if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, - D3D10_CREATE_DEVICE_BGRA_SUPPORT | - D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, - D3D10_FEATURE_LEVEL_9_3, - D3D10_1_SDK_VERSION, &device))) { - - SetDWORDRegKey(metroDX10Available, 0); - return false; - } - } - } - - - SetDWORDRegKey(metroDX10Available, 1); - return true; + bool check = D3DFeatureLevelCheck(); + SetDWORDRegKey(metroDX10Available, check); + return check; } bool diff --git a/browser/metro/shell/commandexecutehandler/CEHHelper.h b/browser/metro/shell/commandexecutehandler/CEHHelper.h index 52f41a328048..25e3333e1018 100644 --- a/browser/metro/shell/commandexecutehandler/CEHHelper.h +++ b/browser/metro/shell/commandexecutehandler/CEHHelper.h @@ -9,15 +9,11 @@ #define _WIN32_WINNT 0x602 #include -#include -#include -#include #include #include //#define SHOW_CONSOLE 1 extern HANDLE sCon; -extern LPCWSTR metroDX10Available; void Log(const wchar_t *fmt, ...); diff --git a/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp b/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp index 2a4c11326638..490fac2dc8f6 100644 --- a/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp +++ b/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp @@ -765,6 +765,11 @@ IFACEMETHODIMP CExecuteCommandVerb::Execute() return E_FAIL; } + if (!IsDX10Available()) { + Log(L"Can't launch in metro due to missing hardware acceleration features."); + mRequestType = DESKTOP_RESTART; + } + // Deal with metro restart for an update - launch desktop with a command // that tells it to run updater then launch the metro browser. if (mRequestType == METRO_UPDATE) { diff --git a/widget/nsIWinMetroUtils.idl b/widget/nsIWinMetroUtils.idl index 065350574ef5..4cf57e288eac 100644 --- a/widget/nsIWinMetroUtils.idl +++ b/widget/nsIWinMetroUtils.idl @@ -8,13 +8,19 @@ /** * Integration with the "Metro"/"Modern" UI environment in Windows 8. * - * Note: browser/metro/base/content/browser-scripts.js contains a stub + * Note: browser/metro/base/content/browser.js contains a stub * implementation of this interface for non-Windows systems, for testing and * development purposes only. */ -[scriptable, uuid(dde6eee6-ad11-475b-b7d7-bee8e46e5756)] +[scriptable, uuid(319faae0-82ca-4c2f-8a24-2b2445e5a72a)] interface nsIWinMetroUtils : nsISupports { + /** + * Determine if the current device has the hardware capabilities to run + * in metro mode. + */ + readonly attribute boolean supported; + /** * Determine if the current browser is running in the metro immersive * environment. diff --git a/widget/windows/winrt/MetroD3DCheckHelper.h b/widget/windows/winrt/MetroD3DCheckHelper.h new file mode 100644 index 000000000000..6a44ba701ec4 --- /dev/null +++ b/widget/windows/winrt/MetroD3DCheckHelper.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +/* this file is included by exe stubs, don't pull xpcom into it. */ + +#include +#include +#include + +/* + * Checks to see if the d3d implementation supports feature level 9.3 or + * above. Metrofx can't run on systems that fail this check. + * + * Note, this can hit perf, don't call this unless you absolutely have to. + * Both the ceh and winrt widget code save a cached result in the registry. + */ +static bool D3DFeatureLevelCheck() +{ + HMODULE dxgiModule = LoadLibraryA("dxgi.dll"); + if (!dxgiModule) { + return false; + } + decltype(CreateDXGIFactory1)* createDXGIFactory1 = + (decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, "CreateDXGIFactory1"); + if (!createDXGIFactory1) { + FreeLibrary(dxgiModule); + return false; + } + + HMODULE d3d10module = LoadLibraryA("d3d10_1.dll"); + if (!d3d10module) { + FreeLibrary(dxgiModule); + return false; + } + decltype(D3D10CreateDevice1)* createD3DDevice = + (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, + "D3D10CreateDevice1"); + if (!createD3DDevice) { + FreeLibrary(d3d10module); + FreeLibrary(dxgiModule); + return false; + } + + IDXGIFactory1* factory1; + if (FAILED(createDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory1))) { + FreeLibrary(d3d10module); + FreeLibrary(dxgiModule); + return false; + } + + IDXGIAdapter1* adapter1; + if (FAILED(factory1->EnumAdapters1(0, &adapter1))) { + factory1->Release(); + FreeLibrary(d3d10module); + FreeLibrary(dxgiModule); + return false; + } + + // Try for DX10.1 + ID3D10Device1* device; + if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT | + D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, + D3D10_FEATURE_LEVEL_10_1, + D3D10_1_SDK_VERSION, &device))) { + // Try for DX10 + if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT | + D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, + D3D10_FEATURE_LEVEL_10_0, + D3D10_1_SDK_VERSION, &device))) { + // Try for DX9.3 (we fall back to cairo and cairo has support for D3D 9.3) + if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT | + D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, + D3D10_FEATURE_LEVEL_9_3, + D3D10_1_SDK_VERSION, &device))) { + adapter1->Release(); + factory1->Release(); + FreeLibrary(d3d10module); + FreeLibrary(dxgiModule); + return false; + } + } + } + device->Release(); + adapter1->Release(); + factory1->Release(); + FreeLibrary(d3d10module); + FreeLibrary(dxgiModule); + return true; +} diff --git a/widget/windows/winrt/moz.build b/widget/windows/winrt/moz.build index 41273d8cd39d..825b3319e47a 100644 --- a/widget/windows/winrt/moz.build +++ b/widget/windows/winrt/moz.build @@ -25,6 +25,10 @@ EXTRA_COMPONENTS += [ 'MetroUIUtils.manifest', ] +EXPORTS.mozilla.widget += [ + 'MetroD3DCheckHelper.h', +] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' diff --git a/widget/windows/winrt/nsWinMetroUtils.cpp b/widget/windows/winrt/nsWinMetroUtils.cpp index 016c2c4883b2..4de1d729668d 100644 --- a/widget/windows/winrt/nsWinMetroUtils.cpp +++ b/widget/windows/winrt/nsWinMetroUtils.cpp @@ -9,6 +9,10 @@ #include "FrameworkView.h" #include "MetroApp.h" #include "ToastNotificationHandler.h" +#include "mozilla/Preferences.h" +#include "mozilla/WindowsVersion.h" +#include "nsIWindowsRegKey.h" +#include "mozilla/widget/MetroD3DCheckHelper.h" #include #include @@ -341,5 +345,58 @@ nsWinMetroUtils::GetForeground(bool* aForeground) return NS_OK; } +NS_IMETHODIMP +nsWinMetroUtils::GetSupported(bool *aSupported) +{ + *aSupported = false; + if (!IsWin8OrLater()) { + return NS_OK; + } + + // if last_used_feature_level_idx is set, we've previously created a + // d3d device that's compatible. See gfxEindowsPlatform for details. + if (Preferences::GetInt("gfx.direct3d.last_used_feature_level_idx", -1) != -1) { + *aSupported = true; + return NS_OK; + } + + // if last_used_feature_level_idx isn't set, gfx hasn't attempted to create + // a device yet. This could be a case where d2d is pref'd off or blacklisted + // on desktop, or we tried to create a device and failed. This could also be + // a first run case where we haven't created an accelerated top level window + // yet. + + NS_NAMED_LITERAL_STRING(metroRegValueName, "MetroD3DAvailable"); + NS_NAMED_LITERAL_STRING(metroRegValuePath, "Software\\Mozilla\\Firefox"); + + // Check to see if the ceh launched us, it also does this check and caches + // a flag in the registry. + nsresult rv; + uint32_t value = 0; + nsCOMPtr regKey = + do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv); + if (NS_SUCCEEDED(rv)) { + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + metroRegValuePath, + nsIWindowsRegKey::ACCESS_WRITE); + if (NS_SUCCEEDED(rv)) { + rv = regKey->ReadIntValue(metroRegValueName, &value); + if (NS_SUCCEEDED(rv)) { + *aSupported = (bool)value; + return NS_OK; + } + + // If all else fails, do the check here. This call is costly but + // we shouldn't hit this except in rare situations where the + // ceh never launched the browser that's running. + value = D3DFeatureLevelCheck(); + regKey->WriteIntValue(metroRegValueName, value); + *aSupported = (bool)value; + return NS_OK; + } + } + return NS_OK; +} + } // widget } // mozilla From c7faf66f1e6307c35ccda26d7171c149b0a77b3c Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Fri, 28 Feb 2014 07:37:31 -0600 Subject: [PATCH 11/62] Bug 969831 - Use the new feature level check for desktop browser 'switch to metro' ux elements. r=msamuel --- browser/components/customizableui/src/CustomizableWidgets.jsm | 2 +- browser/components/nsBrowserGlue.js | 2 +- browser/components/places/tests/unit/head_bookmarks.js | 4 ++-- browser/modules/BrowserUITelemetry.jsm | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/browser/components/customizableui/src/CustomizableWidgets.jsm b/browser/components/customizableui/src/CustomizableWidgets.jsm index 5b3cfd5a3a44..0ae0cc6af01a 100644 --- a/browser/components/customizableui/src/CustomizableWidgets.jsm +++ b/browser/components/customizableui/src/CustomizableWidgets.jsm @@ -831,7 +831,7 @@ const CustomizableWidgets = [{ #ifdef XP_WIN #ifdef MOZ_METRO -if (Services.sysinfo.getProperty("hasWindowsTouchInterface")) { +if (Services.metro && Services.metro.supported) { let widgetArgs = {tooltiptext: "switch-to-metro-button2.tooltiptext"}; let brandShortName = BrandBundle.GetStringFromName("brandShortName"); let metroTooltip = CustomizableUI.getLocalizedProperty(widgetArgs, "tooltiptext", diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index c75051c99d15..29e24d8ab0fc 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -1692,7 +1692,7 @@ BrowserGlue.prototype = { }, }; - if (Services.sysinfo.getProperty("hasWindowsTouchInterface")) { + if (Services.metro && Services.metro.supported) { smartBookmarks.Windows8Touch = { title: bundle.GetStringFromName("windows8TouchTitle"), uri: NetUtil.newURI("place:folder=" + diff --git a/browser/components/places/tests/unit/head_bookmarks.js b/browser/components/places/tests/unit/head_bookmarks.js index aa9b53c10282..71a8c608dff8 100644 --- a/browser/components/places/tests/unit/head_bookmarks.js +++ b/browser/components/places/tests/unit/head_bookmarks.js @@ -63,10 +63,10 @@ let (XULAppInfo = { } // Smart bookmarks constants. -let isWin8OrHigher = Services.sysinfo.getProperty("hasWindowsTouchInterface"); +let isMetroSupported = Services.metro && Services.metro.supported; const SMART_BOOKMARKS_VERSION = 6 const SMART_BOOKMARKS_ON_TOOLBAR = 1; -const SMART_BOOKMARKS_ON_MENU = isWin8OrHigher ? 4 : 3; // Takes in count the additional separator. +const SMART_BOOKMARKS_ON_MENU = isMetroSupported ? 4 : 3; // Takes in count the additional separator. // Default bookmarks constants. const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1; diff --git a/browser/modules/BrowserUITelemetry.jsm b/browser/modules/BrowserUITelemetry.jsm index 66402b86b81f..e50290fc9855 100644 --- a/browser/modules/BrowserUITelemetry.jsm +++ b/browser/modules/BrowserUITelemetry.jsm @@ -77,7 +77,7 @@ XPCOMUtils.defineLazyGetter(this, "DEFAULT_AREA_PLACEMENTS", function() { result["PanelUI-contents"].push("characterencoding-button"); } - if (Services.sysinfo.getProperty("hasWindowsTouchInterface")) { + if (Services.metro && Services.metro.supported) { result["PanelUI-contents"].push("switch-to-metro-button"); } From 041f79c2b2722040f16b20c3cd42c7c4fd28a0e5 Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Fri, 28 Feb 2014 09:04:16 -0500 Subject: [PATCH 12/62] bug 960198 make sidebars available from a customizable widget, r=mconley --- .../customizableui/content/panelUI.inc.xul | 5 ++ .../src/CustomizableWidgets.jsm | 69 ++++++++++++++++++ .../customizableWidgets.properties | 3 + browser/themes/linux/Toolbar-inverted.png | Bin 9050 -> 15924 bytes browser/themes/linux/Toolbar.png | Bin 14312 -> 24496 bytes browser/themes/linux/menuPanel.png | Bin 21339 -> 36279 bytes browser/themes/osx/Toolbar-inverted.png | Bin 29570 -> 44110 bytes browser/themes/osx/Toolbar-inverted@2x.png | Bin 72395 -> 107853 bytes browser/themes/osx/Toolbar.png | Bin 27983 -> 43071 bytes browser/themes/osx/Toolbar@2x.png | Bin 75044 -> 110122 bytes browser/themes/osx/browser.css | 17 +++++ browser/themes/osx/menuPanel.png | Bin 24904 -> 40180 bytes browser/themes/osx/menuPanel@2x.png | Bin 55854 -> 86904 bytes browser/themes/shared/browser.inc | 2 +- browser/themes/shared/menupanel.inc.css | 5 ++ browser/themes/shared/toolbarbuttons.inc.css | 4 + browser/themes/windows/Toolbar-aero.png | Bin 13222 -> 22488 bytes browser/themes/windows/Toolbar-inverted.png | Bin 9050 -> 15924 bytes browser/themes/windows/Toolbar-lunaSilver.png | Bin 13928 -> 23760 bytes browser/themes/windows/Toolbar.png | Bin 9463 -> 24493 bytes browser/themes/windows/menuPanel-aero.png | Bin 25939 -> 41245 bytes browser/themes/windows/menuPanel.png | Bin 21339 -> 36275 bytes 22 files changed, 104 insertions(+), 1 deletion(-) diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul index 0093e3632900..aecf46c39648 100644 --- a/browser/components/customizableui/content/panelUI.inc.xul +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -153,6 +153,11 @@ + + +