diff options
| author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-03-27 14:30:38 +0100 |
|---|---|---|
| committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-03-27 14:30:38 +0100 |
| commit | 37f074e127ba1df465b79664fd4d487fad91a2ce (patch) | |
| tree | 5819feae97bbc1684fc70d867b843bd04ac8f411 | |
| parent | 99783e2c7e917224da401ddbd33354c131b3a377 (diff) | |
| parent | 909c9942ce927c3dac5f850d9bc110a66a72d397 (diff) | |
| download | qtwebkit-37f074e127ba1df465b79664fd4d487fad91a2ce.tar.gz | |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I7f624a8e4ba9491c3ec635ffcb66a16c69bf8188
34 files changed, 329 insertions, 131 deletions
diff --git a/.qmake.conf b/.qmake.conf index 7f9e1dacb..357f8176d 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -3,4 +3,4 @@ MODULE_QMAKE_OUTDIR = $$shadowed($$PWD/Tools/qmake) QMAKEPATH += $$PWD/Tools/qmake $$MODULE_QMAKE_OUTDIR load(qt_build_config) -MODULE_VERSION = 5.0.2 +MODULE_VERSION = 5.1.0 diff --git a/Source/JavaScriptCore/JSCTypedArrayStubs.h b/Source/JavaScriptCore/JSCTypedArrayStubs.h index 2e273f66f..91481fab0 100644 --- a/Source/JavaScriptCore/JSCTypedArrayStubs.h +++ b/Source/JavaScriptCore/JSCTypedArrayStubs.h @@ -184,7 +184,10 @@ static EncodedJSValue JSC_HOST_CALL constructJS##name##Array(ExecState* callFram if (length < 0) \ return JSValue::encode(jsUndefined()); \ Structure* structure = JS##name##Array::createStructure(callFrame->globalData(), callFrame->lexicalGlobalObject(), callFrame->lexicalGlobalObject()->objectPrototype()); \ - return JSValue::encode(JS##name##Array::create(structure, callFrame->lexicalGlobalObject(), name##Array::create(length)));\ + RefPtr<name##Array> buffer = name##Array::create(length); \ + if (!buffer) \ + return throwVMError(callFrame, createRangeError(callFrame, "ArrayBuffer size is not a small enough positive integer.")); \ + return JSValue::encode(JS##name##Array::create(structure, callFrame->lexicalGlobalObject(), buffer.release())); \ } TYPED_ARRAY(Uint8, uint8_t); diff --git a/Source/JavaScriptCore/assembler/ARMAssembler.cpp b/Source/JavaScriptCore/assembler/ARMAssembler.cpp index 9655557a5..6912d1ea3 100644 --- a/Source/JavaScriptCore/assembler/ARMAssembler.cpp +++ b/Source/JavaScriptCore/assembler/ARMAssembler.cpp @@ -297,8 +297,15 @@ void ARMAssembler::baseIndexTransfer32(DataTransferTypeA transferType, RegisterI return; } - add(ARMRegisters::S1, base, op2); - dataTransfer32(transferType, srcDst, ARMRegisters::S1, offset); + if (offset <= 0xfffff && offset >= -0xfffff) { + add(ARMRegisters::S0, base, op2); + dataTransfer32(transferType, srcDst, ARMRegisters::S0, offset); + return; + } + + moveImm(offset, ARMRegisters::S0); + add(ARMRegisters::S0, ARMRegisters::S0, op2); + dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0); } void ARMAssembler::dataTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, int32_t offset) @@ -333,8 +340,17 @@ void ARMAssembler::baseIndexTransfer16(DataTransferTypeB transferType, RegisterI return; } - add(ARMRegisters::S1, base, lsl(index, scale)); - dataTransfer16(transferType, srcDst, ARMRegisters::S1, offset); + ARMWord op2 = lsl(index, scale); + + if (offset <= 0xffff && offset >= -0xffff) { + add(ARMRegisters::S0, base, op2); + dataTransfer16(transferType, srcDst, ARMRegisters::S0, offset); + return; + } + + moveImm(offset, ARMRegisters::S0); + add(ARMRegisters::S0, ARMRegisters::S0, op2); + halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0); } void ARMAssembler::dataTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, int32_t offset) diff --git a/Source/JavaScriptCore/assembler/ARMAssembler.h b/Source/JavaScriptCore/assembler/ARMAssembler.h index ebab46d98..18b10179c 100644 --- a/Source/JavaScriptCore/assembler/ARMAssembler.h +++ b/Source/JavaScriptCore/assembler/ARMAssembler.h @@ -402,13 +402,6 @@ namespace JSC { emitInstruction(toARMWord(cc) | MOV | SetConditionalCodes, rd, ARMRegisters::r0, op2); } - static void revertJump(void* instructionStart, RegisterID rd, ARMWord imm) - { - ARMWord* insn = reinterpret_cast<ARMWord*>(instructionStart); - ARMWord* address = getLdrImmAddress(insn); - *address = imm; - } - void bic(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | BIC, rd, rn, op2); @@ -904,7 +897,7 @@ namespace JSC { static void replaceWithJump(void* instructionStart, void* to) { - ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart) - 1; + ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart); intptr_t difference = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(instruction) + DefaultPrefetchOffset * sizeof(ARMWord)); if (!(difference & 1)) { @@ -952,6 +945,17 @@ namespace JSC { } } + static void revertBranchPtrWithPatch(void* instructionStart, RegisterID rn, ARMWord imm) + { + ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart); + + ASSERT((instruction[2] & LdrPcImmediateInstructionMask) == LdrPcImmediateInstruction); + instruction[0] = toARMWord(AL) | ((instruction[2] & 0x0fff0fff) + sizeof(ARMWord)) | RD(ARMRegisters::S1); + *getLdrImmAddress(instruction) = imm; + instruction[1] = toARMWord(AL) | CMP | SetConditionalCodes | RN(rn) | RM(ARMRegisters::S1); + cacheFlush(instruction, 2 * sizeof(ARMWord)); + } + // Address operations static void* getRelocatedAddress(void* code, AssemblerLabel label) diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h index b93ec6e63..aa402e208 100644 --- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h +++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h @@ -1262,6 +1262,20 @@ public: m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm); } +#if OS(LINUX) || OS(QNX) + static void revertJumpTo_movT3movtcmpT2(void* instructionStart, RegisterID left, RegisterID right, uintptr_t imm) + { + uint16_t* address = static_cast<uint16_t*>(instructionStart); + ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm)); + ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm >> 16)); + address[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); + address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right, lo16); + address[2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); + address[3] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right, hi16); + address[4] = OP_CMP_reg_T2 | left; + cacheFlush(address, sizeof(uint16_t) * 5); + } +#else static void revertJumpTo_movT3(void* instructionStart, RegisterID rd, ARMThumbImmediate imm) { ASSERT(imm.isValid()); @@ -1273,6 +1287,7 @@ public: address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, imm); cacheFlush(address, sizeof(uint16_t) * 2); } +#endif ALWAYS_INLINE void mov(RegisterID rd, ARMThumbImmediate imm) { @@ -1858,7 +1873,12 @@ public: { m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0); } - + + void nopw() + { + m_formatter.twoWordOp16Op16(OP_NOP_T2a, OP_NOP_T2b); + } + AssemblerLabel labelIgnoringWatchpoints() { return m_formatter.label(); @@ -1878,7 +1898,10 @@ public: { AssemblerLabel result = m_formatter.label(); while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { - nop(); + if (UNLIKELY(static_cast<int>(result.m_offset) + 4 <= m_indexOfTailOfLastWatchpoint)) + nopw(); + else + nop(); result = m_formatter.label(); } return result; @@ -2136,15 +2159,31 @@ public: { ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1)); ASSERT(!(bitwise_cast<uintptr_t>(to) & 1)); + +#if OS(LINUX) || OS(QNX) + if (canBeJumpT4(reinterpret_cast<uint16_t*>(instructionStart), to)) { + uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2; + linkJumpT4(ptr, to); + cacheFlush(ptr - 2, sizeof(uint16_t) * 2); + } else { + uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 5; + linkBX(ptr, to); + cacheFlush(ptr - 5, sizeof(uint16_t) * 5); + } +#else uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2; - linkJumpT4(ptr, to); cacheFlush(ptr - 2, sizeof(uint16_t) * 2); +#endif } static ptrdiff_t maxJumpReplacementSize() { +#if OS(LINUX) || OS(QNX) + return 10; +#else return 4; +#endif } static void replaceWithLoad(void* instructionStart) diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h index e6b5ad383..c5ea9c542 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -673,9 +673,8 @@ public: m_assembler.vmov(dest1, dest2, src); } - void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch) + void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID) { - UNUSED_PARAM(scratch); m_assembler.vmov(dest, src1, src2); } @@ -955,6 +954,7 @@ public: Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) { + ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord)); dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); Jump jump = branch32(cond, left, ARMRegisters::S1, true); return jump; @@ -963,6 +963,7 @@ public: Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) { load32(left, ARMRegisters::S1); + ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord)); dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); return jump; @@ -1215,7 +1216,7 @@ public: // If the result is not representable as a 32 bit value, branch. // May also branch for some values that are representable in 32 bits // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) + void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID) { m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src); m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); @@ -1285,10 +1286,10 @@ public: static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID reg, void* initialValue) { - ARMAssembler::revertJump(instructionStart.dataLocation(), reg, reinterpret_cast<uintptr_t>(initialValue) & 0xffff); + ARMAssembler::revertBranchPtrWithPatch(instructionStart.dataLocation(), reg, reinterpret_cast<uintptr_t>(initialValue) & 0xffff); } - static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue) + static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*) { UNREACHABLE_FOR_PLATFORM(); } diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h index 8d7a3a69a..06d0e1534 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -1767,9 +1767,14 @@ public: return label.labelAtOffset(-twoWordOpSize * 2); } - static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue) + static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue) { +#if OS(LINUX) || OS(QNX) + ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue)); +#else + UNUSED_PARAM(rd); ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff)); +#endif } static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 00209f236..fe9f6ac7c 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -568,7 +568,7 @@ void CodeBlock::dumpBytecode() dataLogF("\nException Handlers:\n"); unsigned i = 0; do { - dataLogF("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target); + dataLogF("\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target, m_rareData->m_exceptionHandlers[i].scopeDepth); ++i; } while (i < m_rareData->m_exceptionHandlers.size()); } @@ -2473,7 +2473,7 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) for (size_t i = 0; i < exceptionHandlers.size(); ++i) { // Handlers are ordered innermost first, so the first handler we encounter // that contains the source address is the correct handler to use. - if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset) + if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end > bytecodeOffset) return &exceptionHandlers[i]; } diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 35976257b..507241696 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -157,10 +157,38 @@ ParserError BytecodeGenerator::generate() for (unsigned i = 0; i < m_tryRanges.size(); ++i) { TryRange& range = m_tryRanges[i]; + int start = range.start->bind(); + int end = range.end->bind(); + + // This will happen for empty try blocks and for some cases of finally blocks: + // + // try { + // try { + // } finally { + // return 42; + // // *HERE* + // } + // } finally { + // print("things"); + // } + // + // The return will pop scopes to execute the outer finally block. But this includes + // popping the try context for the inner try. The try context is live in the fall-through + // part of the finally block not because we will emit a handler that overlaps the finally, + // but because we haven't yet had a chance to plant the catch target. Then when we finish + // emitting code for the outer finally block, we repush the try contex, this time with a + // new start index. But that means that the start index for the try range corresponding + // to the inner-finally-following-the-return (marked as "*HERE*" above) will be greater + // than the end index of the try block. This is harmless since end < start handlers will + // never get matched in our logic, but we do the runtime a favor and choose to not emit + // such handlers at all. + if (end <= start) + continue; + ASSERT(range.tryData->targetScopeDepth != UINT_MAX); UnlinkedHandlerInfo info = { - static_cast<uint32_t>(range.start->bind(0, 0)), static_cast<uint32_t>(range.end->bind(0, 0)), - static_cast<uint32_t>(range.tryData->target->bind(0, 0)), + static_cast<uint32_t>(start), static_cast<uint32_t>(end), + static_cast<uint32_t>(range.tryData->target->bind()), range.tryData->targetScopeDepth }; m_codeBlock->addExceptionHandler(info); diff --git a/Source/JavaScriptCore/bytecompiler/Label.h b/Source/JavaScriptCore/bytecompiler/Label.h index 21fa46309..8b444de91 100644 --- a/Source/JavaScriptCore/bytecompiler/Label.h +++ b/Source/JavaScriptCore/bytecompiler/Label.h @@ -66,6 +66,12 @@ namespace JSC { int refCount() const { return m_refCount; } bool isForward() const { return m_location == invalidLocation; } + + int bind() + { + ASSERT(!isForward()); + return bind(0, 0); + } private: typedef Vector<std::pair<int, int>, 8> JumpVector; diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index d9ae4a274..52cebf80f 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -305,8 +305,6 @@ private: dataLogF(" Original has local r%d.\n", originalNode->local()); #endif ASSERT(child.local() == originalNode->local()); - if (changeRef) - ASSERT(originalNode->shouldGenerate()); // Possibilities: // SetLocal -> the secondBlock is getting the value of something that is immediately // available in the first block with a known NodeIndex. @@ -326,6 +324,8 @@ private: } switch (originalNode->op()) { case SetLocal: { + if (changeRef) + ASSERT(originalNode->shouldGenerate()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" It's a SetLocal.\n"); #endif @@ -336,11 +336,16 @@ private: #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" It's a GetLocal.\n"); #endif - m_graph.changeIndex(edge, originalNodeIndex, changeRef); + if (originalNode->shouldGenerate()) + m_graph.changeIndex(edge, originalNodeIndex, changeRef); + // If we have a GetLocal that points to a child GetLocal that is dead, then + // we have no need to do anything: this original GetLocal is still valid. break; } case Phi: case SetArgument: { + if (changeRef) + ASSERT(originalNode->shouldGenerate()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" It's Phi/SetArgument.\n"); #endif diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index d91d37394..b39845968 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -72,6 +72,12 @@ struct PutToBaseOperationData { unsigned putToBaseOperationIndex; }; +enum AddSpeculationMode { + DontSpeculateInteger, + SpeculateIntegerButAlwaysWatchOverflow, + SpeculateInteger +}; + // // === Graph === @@ -209,7 +215,7 @@ public: return speculationFromValue(node.valueOfJSConstant(m_codeBlock)); } - bool addShouldSpeculateInteger(Node& add) + AddSpeculationMode addSpeculationMode(Node& add) { ASSERT(add.op() == ValueAdd || add.op() == ArithAdd || add.op() == ArithSub); @@ -221,7 +227,12 @@ public: if (right.hasConstant()) return addImmediateShouldSpeculateInteger(add, left, right); - return Node::shouldSpeculateIntegerExpectingDefined(left, right) && add.canSpeculateInteger(); + return (Node::shouldSpeculateIntegerExpectingDefined(left, right) && add.canSpeculateInteger()) ? SpeculateInteger : DontSpeculateInteger; + } + + bool addShouldSpeculateInteger(Node& add) + { + return addSpeculationMode(add) != DontSpeculateInteger; } bool mulShouldSpeculateInteger(Node& mul) @@ -699,26 +710,26 @@ private: void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex); - bool addImmediateShouldSpeculateInteger(Node& add, Node& variable, Node& immediate) + AddSpeculationMode addImmediateShouldSpeculateInteger(Node& add, Node& variable, Node& immediate) { ASSERT(immediate.hasConstant()); JSValue immediateValue = immediate.valueOfJSConstant(m_codeBlock); if (!immediateValue.isNumber()) - return false; + return DontSpeculateInteger; if (!variable.shouldSpeculateIntegerExpectingDefined()) - return false; + return DontSpeculateInteger; if (immediateValue.isInt32()) - return add.canSpeculateInteger(); + return add.canSpeculateInteger() ? SpeculateInteger : DontSpeculateInteger; double doubleImmediate = immediateValue.asDouble(); const double twoToThe48 = 281474976710656.0; if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48) - return false; + return DontSpeculateInteger; - return nodeCanTruncateInteger(add.arithNodeFlags()); + return nodeCanTruncateInteger(add.arithNodeFlags()) ? SpeculateIntegerButAlwaysWatchOverflow : DontSpeculateInteger; } bool mulImmediateShouldSpeculateInteger(Node& mul, Node& variable, Node& immediate) diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 4b8a17285..5b6c28ff7 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -285,9 +285,11 @@ private: SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); + AddSpeculationMode mode = DontSpeculateInteger; + if (left && right) { if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) { - if (m_graph.addShouldSpeculateInteger(node)) + if ((mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); @@ -303,6 +305,9 @@ private: if (m_graph[node.child1()].hasNumberResult() || m_graph[node.child2()].hasNumberResult()) flags &= ~NodeUsedAsOther; + if (mode != SpeculateInteger) + flags |= NodeUsedAsNumber; + changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; @@ -312,8 +317,10 @@ private: SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); + AddSpeculationMode mode = DontSpeculateInteger; + if (left && right) { - if (m_graph.addShouldSpeculateInteger(node)) + if ((mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); @@ -323,6 +330,9 @@ private: flags &= ~NodeNeedsNegZero; flags &= ~NodeUsedAsOther; + if (mode != SpeculateInteger) + flags |= NodeUsedAsNumber; + changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; @@ -332,8 +342,10 @@ private: SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); + AddSpeculationMode mode = DontSpeculateInteger; + if (left && right) { - if (m_graph.addShouldSpeculateInteger(node)) + if ((mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); @@ -343,6 +355,9 @@ private: flags &= ~NodeNeedsNegZero; flags &= ~NodeUsedAsOther; + if (mode != SpeculateInteger) + flags |= NodeUsedAsNumber; + changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; @@ -721,6 +736,10 @@ private: break; case PutScopedVar: + changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); + changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue); + break; + case Return: case Throw: changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index 07a509061..9a7e7df70 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -341,7 +341,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier return false; PropertyOffset offset = slot.cachedOffset(); - size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset); + size_t count = normalizePrototypeChainForChainAccess(exec, baseValue, slot.slotBase(), propertyName, offset); if (count == InvalidPrototypeChain) return false; @@ -569,7 +569,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I ASSERT(slot.slotBase().isObject()); PropertyOffset offset = slot.cachedOffset(); - size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset); + size_t count = normalizePrototypeChainForChainAccess(exec, baseValue, slot.slotBase(), propertyName, offset); if (count == InvalidPrototypeChain) return false; diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp index 9d6060d60..4ee723d84 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp @@ -201,7 +201,7 @@ public: if (!value || !value.isCell()) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("Zeroing the structure to hoist for %s because the OSR entry value is not a cell: %s.\n", - m_graph.nameOfVariableAccessData(variable), value.description()); + m_graph.nameOfVariableAccessData(variable), value); #endif iter->value.m_structure = 0; continue; diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 9b69d1b3d..7d9e6f92e 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -785,9 +785,12 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV JSScope* scope = callFrame->scope(); int scopeDelta = 0; if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode - || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - scopeDelta = depth(codeBlock, scope) - handler->scopeDepth; - ASSERT(scopeDelta >= 0); + || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) { + int currentDepth = depth(codeBlock, scope); + int targetDepth = handler->scopeDepth; + scopeDelta = currentDepth - targetDepth; + ASSERT(scopeDelta >= 0); + } while (scopeDelta--) scope = scope->next(); callFrame->setScope(scope); diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index f47ac08ef..fbef1fcb9 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -908,6 +908,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -916,6 +917,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -934,6 +936,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co } if (structure->isDictionary()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -943,6 +946,12 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co JSObject* slotBaseObject = asObject(slot.slotBase()); size_t offset = slot.cachedOffset(); + + if (structure->typeInfo().hasImpureGetOwnPropertySlot()) { + stubInfo->accessType = access_get_by_id_generic; + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. @@ -960,9 +969,10 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co } PropertyOffset offset = slot.cachedOffset(); - size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); + size_t count = normalizePrototypeChainForChainAccess(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (count == InvalidPrototypeChain) { stubInfo->accessType = access_get_by_id_generic; + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -1689,6 +1699,12 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); else if (slot.slotBase() == baseValue.asCell()->structure()->prototypeForLookup(callFrame)) { ASSERT(!baseValue.asCell()->structure()->isDictionary()); + + if (baseValue.asCell()->structure()->typeInfo().hasImpureGetOwnPropertySlot()) { + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + return JSValue::encode(result); + } + // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) { @@ -1705,7 +1721,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } } else { - size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); + size_t count = normalizePrototypeChainForChainAccess(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (count == InvalidPrototypeChain) { ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); diff --git a/Source/JavaScriptCore/llint/LLIntExceptions.cpp b/Source/JavaScriptCore/llint/LLIntExceptions.cpp index 5e6bba365..17c15aa51 100644 --- a/Source/JavaScriptCore/llint/LLIntExceptions.cpp +++ b/Source/JavaScriptCore/llint/LLIntExceptions.cpp @@ -50,7 +50,7 @@ void interpreterThrowInCaller(ExecState* exec, ReturnAddressPtr pc) JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); #if LLINT_SLOW_PATH_TRACING - dataLogF("Throwing exception %s.\n", globalData->exception.description()); + dataLog("Throwing exception ", globalData->exception, ".\n"); #endif fixupPCforExceptionIfNeeded(exec); genericThrow( @@ -69,7 +69,7 @@ Instruction* returnToThrow(ExecState* exec, Instruction* pc) JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); #if LLINT_SLOW_PATH_TRACING - dataLogF("Throwing exception %s (returnToThrow).\n", globalData->exception.description()); + dataLog("Throwing exception ", globalData->exception, " (returnToThrow).\n"); #endif fixupPCforExceptionIfNeeded(exec); genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin()); @@ -82,7 +82,7 @@ void* callToThrow(ExecState* exec, Instruction* pc) JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); #if LLINT_SLOW_PATH_TRACING - dataLogF("Throwing exception %s (callToThrow).\n", globalData->exception.description()); + dataLog("Throwing exception ", globalData->exception, " (callToThrow).\n"); #endif fixupPCforExceptionIfNeeded(exec); genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin()); diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index 584100e50..0bd19d46f 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -635,8 +635,7 @@ LLINT_SLOW_PATH_DECL(slow_path_add) JSValue v2 = LLINT_OP_C(3).jsValue(); #if LLINT_SLOW_PATH_TRACING - dataLogF("Trying to add %s", v1.description()); - dataLogF(" to %s.\n", v2.description()); + dataLog("Trying to add ", v1, " to ", v2, ".\n"); #endif if (v1.isString() && !v2.isObject()) @@ -1367,7 +1366,7 @@ static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, } #if LLINT_SLOW_PATH_TRACING - dataLogF("Call callee is not a function: %s\n", callee.description()); + dataLog("Call callee is not a function: ", callee, "\n"); #endif ASSERT(callType == CallTypeNone); @@ -1390,7 +1389,7 @@ static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, } #if LLINT_SLOW_PATH_TRACING - dataLogF("Constructor callee is not a function: %s\n", callee.description()); + dataLog("Constructor callee is not a function: ", callee, "\n"); #endif ASSERT(constructType == ConstructTypeNone); diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp b/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp index a9cb393b0..b2ce2483e 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp @@ -116,6 +116,17 @@ static double Ints2Double(uint32_t lo, uint32_t hi) u.ival64 = (static_cast<uint64_t>(hi) << 32) | lo; return u.dval; } + +static void Double2Ints(double val, uint32_t& lo, uint32_t& hi) +{ + union { + double dval; + uint64_t ival64; + } u; + u.dval = val; + hi = static_cast<uint32_t>(u.ival64 >> 32); + lo = static_cast<uint32_t>(u.ival64); +} #endif // USE(JSVALUE32_64) } // namespace LLint diff --git a/Source/JavaScriptCore/offlineasm/ast.rb b/Source/JavaScriptCore/offlineasm/ast.rb index 9333247dc..4f0c3fd88 100644 --- a/Source/JavaScriptCore/offlineasm/ast.rb +++ b/Source/JavaScriptCore/offlineasm/ast.rb @@ -1139,7 +1139,7 @@ class Not < Node end def children - [@left, @right] + [@child] end def mapChildren diff --git a/Source/JavaScriptCore/offlineasm/cloop.rb b/Source/JavaScriptCore/offlineasm/cloop.rb index cbe7e2ca1..8d0838ebd 100644 --- a/Source/JavaScriptCore/offlineasm/cloop.rb +++ b/Source/JavaScriptCore/offlineasm/cloop.rb @@ -1025,7 +1025,7 @@ class Instruction # 32-bit instruction: f2dii dblOp int32LoOp int32HiOp (based on ARMv7) # Encode a 64-bit double into 2 32-bit ints (low and high). when "fd2ii" - $asm.putc "Double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clValue}, #{operands[2].clValue});" + $asm.putc "Double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clValue(:uint32)}, #{operands[2].clValue(:uint32)});" # 64-bit instruction: fq2d int64Op dblOp (based on X64) # Copy a bit-encoded double in a 64-bit int register to a double register. diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index 6f63260fe..97fc64c1c 100644 --- a/Source/JavaScriptCore/runtime/JSTypeInfo.h +++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h @@ -46,6 +46,7 @@ namespace JSC { static const unsigned OverridesVisitChildren = 1 << 7; static const unsigned OverridesGetPropertyNames = 1 << 8; static const unsigned ProhibitsPropertyCaching = 1 << 9; + static const unsigned HasImpureGetOwnPropertySlot = 1 << 10; class TypeInfo { public: @@ -54,7 +55,6 @@ namespace JSC { , m_flags(flags & 0xff) , m_flags2(flags >> 8) { - ASSERT(flags <= 0x3ff); ASSERT(static_cast<int>(type) <= 0xff); ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren)); // No object that doesn't ImplementsHasInstance should override it! @@ -80,6 +80,7 @@ namespace JSC { bool overridesVisitChildren() const { return isSetOnFlags1(OverridesVisitChildren); } bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); } bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); } + bool hasImpureGetOwnPropertySlot() const { return isSetOnFlags2(HasImpureGetOwnPropertySlot); } static ptrdiff_t flagsOffset() { diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index 7301bf6ec..8e0a0a393 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -302,15 +302,18 @@ namespace JSC { #define InvalidPrototypeChain (std::numeric_limits<size_t>::max()) - inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset) + inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset) { JSCell* cell = base.asCell(); size_t count = 0; - + while (slotBase != cell) { if (cell->isProxy()) return InvalidPrototypeChain; + if (cell->structure()->typeInfo().hasImpureGetOwnPropertySlot()) + return InvalidPrototypeChain; + JSValue v = cell->structure()->prototypeForLookup(callFrame); // If we didn't find slotBase in base's prototype chain, then base @@ -328,7 +331,7 @@ namespace JSC { if (slotBase == cell) slotOffset = cell->structure()->get(callFrame->globalData(), propertyName); } - + ++count; } diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm index 0578f46b4..be7f1d1aa 100644 --- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm +++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm @@ -783,16 +783,23 @@ sub GenerateHeader $implIncludes{"${className}Custom.h"} = 1 if !$interface->extendedAttributes->{"JSCustomHeader"} && ($interface->extendedAttributes->{"CustomPutFunction"} || $interface->extendedAttributes->{"CustomNamedSetter"}); + my $hasImpureNamedGetter = + $interface->extendedAttributes->{"NamedGetter"} + || $interface->extendedAttributes->{"CustomNamedGetter"} + || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}; + my $hasComplexGetter = $interface->extendedAttributes->{"IndexedGetter"} || $interface->extendedAttributes->{"NumericIndexedGetter"} - || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"} || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"} - || $interface->extendedAttributes->{"NamedGetter"} - || $interface->extendedAttributes->{"CustomNamedGetter"}; + || $hasImpureNamedGetter; my $hasGetter = $numAttributes > 0 || !$interface->extendedAttributes->{"OmitConstructor"} || $hasComplexGetter; + if ($hasImpureNamedGetter) { + $structureFlags{"JSC::HasImpureGetOwnPropertySlot"} = 1; + } + # Getters if ($hasGetter) { push(@headerContent, " static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n"); diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 5716e39d3..7fc354d16 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -739,6 +739,7 @@ bool FrameLoader::allAncestorsAreComplete() const void FrameLoader::checkCompleted() { + RefPtr<Frame> protect(m_frame); m_shouldCallCheckCompleted = false; if (m_frame->view()) @@ -769,7 +770,6 @@ void FrameLoader::checkCompleted() m_requestedHistoryItem = 0; m_frame->document()->setReadyState(Document::Complete); - RefPtr<Frame> protect(m_frame); checkCallImplicitClose(); // if we didn't do it before m_frame->navigationScheduler()->startTimer(); diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 33dc945e9..6c341ddb2 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -263,6 +263,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle if (viewStyle->writingMode() != newStyle->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) { viewStyle->setWritingMode(newStyle->writingMode()); viewRenderer->setHorizontalWritingMode(newStyle->isHorizontalWritingMode()); + viewRenderer->markAllDescendantsWithFloatsForLayout(); if (isBodyRenderer) { document()->documentElement()->renderer()->style()->setWritingMode(newStyle->writingMode()); document()->documentElement()->renderer()->setHorizontalWritingMode(newStyle->isHorizontalWritingMode()); diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp index 543c2d353..e4e7e24bb 100644 --- a/Source/WebCore/rendering/RenderFrameSet.cpp +++ b/Source/WebCore/rendering/RenderFrameSet.cpp @@ -131,14 +131,14 @@ void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) LayoutPoint adjustedPaintOffset = paintOffset + location(); - int rows = frameSet()->totalRows(); - int cols = frameSet()->totalCols(); + size_t rows = m_rows.m_sizes.size(); + size_t cols = m_cols.m_sizes.size(); LayoutUnit borderThickness = frameSet()->border(); LayoutUnit yPos = 0; - for (int r = 0; r < rows; r++) { + for (size_t r = 0; r < rows; r++) { LayoutUnit xPos = 0; - for (int c = 0; c < cols; c++) { + for (size_t c = 0; c < cols; c++) { child->paint(paintInfo, adjustedPaintOffset); xPos += m_cols.m_sizes[c]; if (borderThickness && m_cols.m_allowBorder[c + 1]) { diff --git a/Source/WebKit2/UIProcess/PageViewportController.cpp b/Source/WebKit2/UIProcess/PageViewportController.cpp index 05ff8b98a..a34782c8f 100644 --- a/Source/WebKit2/UIProcess/PageViewportController.cpp +++ b/Source/WebKit2/UIProcess/PageViewportController.cpp @@ -45,7 +45,6 @@ PageViewportController::PageViewportController(WebKit::WebPageProxy* proxy, Page , m_allowsUserScaling(false) , m_minimumScaleToFit(1) , m_initiallyFitToViewport(true) - , m_hasSuspendedContent(false) , m_hadUserInteraction(false) , m_pageScaleFactor(1) , m_viewportPosIsLocked(false) @@ -177,7 +176,7 @@ void PageViewportController::pageTransitionViewportReady() void PageViewportController::pageDidRequestScroll(const IntPoint& cssPosition) { // Ignore the request if suspended. Can only happen due to delay in event delivery. - if (m_hasSuspendedContent) + if (m_webPageProxy->areActiveDOMObjectsAndAnimationsSuspended()) return; FloatRect endVisibleContentRect(clampViewportToContents(cssPosition, m_pageScaleFactor), viewportSizeInContentsCoordinates()); @@ -246,26 +245,6 @@ WebCore::FloatSize PageViewportController::viewportSizeInContentsCoordinates() c return WebCore::FloatSize(m_viewportSize.width() / m_pageScaleFactor, m_viewportSize.height() / m_pageScaleFactor); } -void PageViewportController::suspendContent() -{ - if (m_hasSuspendedContent) - return; - - m_hasSuspendedContent = true; - m_webPageProxy->suspendActiveDOMObjectsAndAnimations(); -} - -void PageViewportController::resumeContent() -{ - m_client->didResumeContent(); - - if (!m_hasSuspendedContent) - return; - - m_hasSuspendedContent = false; - m_webPageProxy->resumeActiveDOMObjectsAndAnimations(); -} - void PageViewportController::applyScaleAfterRenderingContents(float scale) { m_pageScaleFactor = scale; @@ -295,7 +274,7 @@ bool PageViewportController::updateMinimumScaleToFit(bool userInitiatedUpdate) if (!fuzzyCompare(minimumScale, m_minimumScaleToFit, 0.001)) { m_minimumScaleToFit = minimumScale; - if (!hasSuspendedContent()) { + if (!m_webPageProxy->areActiveDOMObjectsAndAnimationsSuspended()) { if (!m_hadUserInteraction || (userInitiatedUpdate && currentlyScaledToFit)) applyScaleAfterRenderingContents(m_minimumScaleToFit); else { diff --git a/Source/WebKit2/UIProcess/PageViewportController.h b/Source/WebKit2/UIProcess/PageViewportController.h index dadbbbefe..fcc4e170d 100644 --- a/Source/WebKit2/UIProcess/PageViewportController.h +++ b/Source/WebKit2/UIProcess/PageViewportController.h @@ -22,8 +22,6 @@ #ifndef PageViewportController_h #define PageViewportController_h -#if USE(TILED_BACKING_STORE) - #include <WebCore/FloatPoint.h> #include <WebCore/FloatRect.h> #include <WebCore/FloatSize.h> @@ -47,14 +45,10 @@ public: PageViewportController(WebKit::WebPageProxy*, PageViewportControllerClient*); virtual ~PageViewportController() { } - void suspendContent(); - void resumeContent(); - float innerBoundedViewportScale(float) const; float outerBoundedViewportScale(float) const; WebCore::FloatPoint clampViewportToContents(const WebCore::FloatPoint& viewportPos, float viewportScale); - bool hasSuspendedContent() const { return m_hasSuspendedContent; } bool hadUserInteraction() const { return m_hadUserInteraction; } bool allowsUserScaling() const { return m_allowsUserScaling; } @@ -94,7 +88,6 @@ private: float m_minimumScaleToFit; bool m_initiallyFitToViewport; - bool m_hasSuspendedContent; bool m_hadUserInteraction; WebCore::FloatPoint m_viewportPos; @@ -112,6 +105,4 @@ bool fuzzyCompare(float, float, float epsilon); } // namespace WebKit -#endif - #endif // PageViewportController_h diff --git a/Source/WebKit2/UIProcess/WebPageProxy.h b/Source/WebKit2/UIProcess/WebPageProxy.h index ff8ec5133..1b2e9a2b7 100644 --- a/Source/WebKit2/UIProcess/WebPageProxy.h +++ b/Source/WebKit2/UIProcess/WebPageProxy.h @@ -472,6 +472,7 @@ public: void setCustomTextEncodingName(const String&); String customTextEncodingName() const { return m_customTextEncodingName; } + bool areActiveDOMObjectsAndAnimationsSuspended() const { return m_isPageSuspended; } void resumeActiveDOMObjectsAndAnimations(); void suspendActiveDOMObjectsAndAnimations(); diff --git a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp index c0eb16ab9..61f2aaf57 100644 --- a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp +++ b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp @@ -23,12 +23,14 @@ #include "config.h" #include "PageViewportControllerClientQt.h" +#include "WebPageProxy.h" #include "qquickwebpage_p.h" #include "qquickwebview_p.h" #include "qwebkittest_p.h" #include <QPointF> #include <QTransform> #include <QtQuick/qquickitem.h> +#include <WKAPICast.h> #include <WebCore/FloatRect.h> #include <WebCore/FloatSize.h> @@ -41,12 +43,14 @@ static const int kScaleAnimationDurationMillis = 250; PageViewportControllerClientQt::PageViewportControllerClientQt(QQuickWebView* viewportItem, QQuickWebPage* pageItem) : m_viewportItem(viewportItem) , m_pageItem(pageItem) + , m_scaleChange(this) + , m_scrollChange(this) + , m_touchInteraction(this, false /* shouldSuspend */) , m_scaleAnimation(new ScaleAnimation(this)) + , m_activeInteractionCount(0) , m_pinchStartScale(-1) , m_lastCommittedScale(-1) , m_zoomOutScale(0) - , m_isUserInteracting(false) - , m_ignoreViewportChanges(false) { m_scaleAnimation->setDuration(kScaleAnimationDurationMillis); m_scaleAnimation->setEasingCurve(QEasingCurve::OutCubic); @@ -76,6 +80,32 @@ void PageViewportControllerClientQt::ScaleAnimation::updateCurrentValue(const QV m_controllerClient->setContentRectVisiblePositionAtScale(itemRect.topLeft(), itemScale); } +void PageViewportControllerClientQt::ViewportInteractionTracker::begin() +{ + if (m_inProgress) + return; + + m_inProgress = true; + + if (m_shouldSuspend) + toImpl(m_controllerClient->m_viewportItem->pageRef())->suspendActiveDOMObjectsAndAnimations(); + + ++(m_controllerClient->m_activeInteractionCount); +} + +void PageViewportControllerClientQt::ViewportInteractionTracker::end() +{ + if (!m_inProgress) + return; + + m_inProgress = false; + + ASSERT(m_controllerClient->m_activeInteractionCount > 0); + + if (!(--(m_controllerClient->m_activeInteractionCount))) + toImpl(m_controllerClient->m_viewportItem->pageRef())->resumeActiveDOMObjectsAndAnimations(); +} + PageViewportControllerClientQt::~PageViewportControllerClientQt() { } @@ -103,7 +133,8 @@ void PageViewportControllerClientQt::animateContentRectVisible(const QRectF& con QRectF viewportRectInContentCoords = m_viewportItem->mapRectToWebContent(m_viewportItem->boundingRect()); if (contentRect == viewportRectInContentCoords) { - m_controller->resumeContent(); + m_scaleChange.end(); + updateViewportController(); return; } @@ -121,22 +152,20 @@ void PageViewportControllerClientQt::animateContentRectVisible(const QRectF& con void PageViewportControllerClientQt::flickMoveStarted() { - m_controller->suspendContent(); - + m_scrollChange.begin(); m_lastScrollPosition = m_viewportItem->contentPos(); } void PageViewportControllerClientQt::flickMoveEnded() { // This method is called on the end of the pan or pan kinetic animation. - - if (!m_isUserInteracting) - m_controller->resumeContent(); + m_scrollChange.end(); + updateViewportController(); } void PageViewportControllerClientQt::pageItemPositionChanged() { - if (m_ignoreViewportChanges) + if (m_scaleChange.inProgress()) return; QPointF newPosition = m_viewportItem->contentPos(); @@ -150,13 +179,11 @@ void PageViewportControllerClientQt::scaleAnimationStateChanged(QAbstractAnimati { switch (newState) { case QAbstractAnimation::Running: - m_ignoreViewportChanges = true; - m_viewportItem->cancelFlick(); - m_controller->suspendContent(); + m_scaleChange.begin(); break; case QAbstractAnimation::Stopped: - m_ignoreViewportChanges = false; - m_controller->resumeContent(); + m_scaleChange.end(); + updateViewportController(); break; default: break; @@ -167,13 +194,14 @@ void PageViewportControllerClientQt::touchBegin() { m_controller->setHadUserInteraction(true); - // Prevents resuming the page between the user's flicks of the page. - m_isUserInteracting = true; + // Prevent resuming the page during transition between gestures while the user is interacting. + // The content is suspended as soon as a pan or pinch gesture or an animation is started. + m_touchInteraction.begin(); } void PageViewportControllerClientQt::touchEnd() { - m_isUserInteracting = false; + m_touchInteraction.end(); } void PageViewportControllerClientQt::focusEditableArea(const QRectF& caretArea, const QRectF& targetArea) @@ -217,7 +245,7 @@ void PageViewportControllerClientQt::zoomToAreaGestureEnded(const QPointF& touch if (!targetArea.isValid()) return; - if (m_controller->hasSuspendedContent()) + if (m_scrollChange.inProgress() || m_scaleChange.inProgress()) return; const float margin = 10; // We want at least a little bit of margin. @@ -425,9 +453,7 @@ void PageViewportControllerClientQt::pinchGestureStarted(const QPointF& pinchCen return; clearRelativeZoomState(); - - m_ignoreViewportChanges = true; - m_controller->suspendContent(); + m_scaleChange.begin(); m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates; m_pinchStartScale = m_pageItem->contentsScale(); @@ -435,11 +461,12 @@ void PageViewportControllerClientQt::pinchGestureStarted(const QPointF& pinchCen void PageViewportControllerClientQt::pinchGestureRequestUpdate(const QPointF& pinchCenterInViewportCoordinates, qreal totalScaleFactor) { - ASSERT(m_controller->hasSuspendedContent()); + ASSERT(m_scaleChange.inProgress()); if (!m_controller->allowsUserScaling()) return; + ASSERT(m_pinchStartScale > 0); // Changes of the center position should move the page even if the zoom factor does not change. const qreal pinchScale = m_pinchStartScale * totalScaleFactor; @@ -456,12 +483,11 @@ void PageViewportControllerClientQt::pinchGestureRequestUpdate(const QPointF& pi void PageViewportControllerClientQt::pinchGestureEnded() { - ASSERT(m_controller->hasSuspendedContent()); + ASSERT(m_scaleChange.inProgress()); if (!m_controller->allowsUserScaling()) return; - m_ignoreViewportChanges = false; m_pinchStartScale = -1; // This will take care of resuming the content, even if no animation was performed. @@ -471,7 +497,8 @@ void PageViewportControllerClientQt::pinchGestureEnded() void PageViewportControllerClientQt::pinchGestureCancelled() { m_pinchStartScale = -1; - m_controller->resumeContent(); + m_scaleChange.end(); + updateViewportController(); } void PageViewportControllerClientQt::didChangeContentsSize(const IntSize& newSize) @@ -482,7 +509,7 @@ void PageViewportControllerClientQt::didChangeContentsSize(const IntSize& newSiz // we didn't do scale adjustment. emit m_viewportItem->experimental()->test()->contentsScaleCommitted(); - if (!m_controller->hasSuspendedContent()) + if (!m_scaleChange.inProgress() && !m_scrollChange.inProgress()) setContentsRectToNearestValidBounds(); } diff --git a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h index 687f29193..22c4c3d3c 100644 --- a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h +++ b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h @@ -103,6 +103,24 @@ private: virtual void updateCurrentValue(const QVariant&); }; + class ViewportInteractionTracker { + public: + ViewportInteractionTracker(PageViewportControllerClientQt* client, bool shouldSuspend = true) + : m_controllerClient(client) + , m_shouldSuspend(shouldSuspend) + , m_inProgress(false) + { } + + void begin(); + void end(); + bool inProgress() const { return m_inProgress; } + + private: + PageViewportControllerClientQt* m_controllerClient; + bool m_shouldSuspend; + bool m_inProgress; + }; + struct ScaleStackItem { ScaleStackItem(qreal scale, qreal xPosition) : scale(scale) @@ -113,6 +131,7 @@ private: qreal xPosition; }; + friend class ViewportInteractionTracker; friend class ScaleAnimation; friend class ::QWebKitTest; @@ -130,15 +149,18 @@ private: void scaleContent(qreal itemScale, const QPointF& centerInCSSCoordinates = QPointF()); void clearRelativeZoomState(); + ViewportInteractionTracker m_scaleChange; + ViewportInteractionTracker m_scrollChange; + ViewportInteractionTracker m_touchInteraction; + ScaleAnimation* m_scaleAnimation; QPointF m_lastPinchCenterInViewportCoordinates; QPointF m_lastScrollPosition; + int m_activeInteractionCount; qreal m_pinchStartScale; qreal m_lastCommittedScale; qreal m_zoomOutScale; QList<ScaleStackItem> m_scaleStack; - bool m_isUserInteracting; - bool m_ignoreViewportChanges; }; } // namespace WebKit diff --git a/Tools/MiniBrowser/qt/raw/View.cpp b/Tools/MiniBrowser/qt/raw/View.cpp index 8e04fd00b..4c4d52855 100644 --- a/Tools/MiniBrowser/qt/raw/View.cpp +++ b/Tools/MiniBrowser/qt/raw/View.cpp @@ -62,7 +62,7 @@ View::View(const QString& url) { setSurfaceType(OpenGLSurface); setGeometry(50, 50, 980, 600); - setWindowFlags(Qt::Window | Qt::WindowTitleHint); + setFlags(Qt::Window | Qt::WindowTitleHint); create(); m_context = new QOpenGLContext; |
