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 /Source/JavaScriptCore | |
parent | 99783e2c7e917224da401ddbd33354c131b3a377 (diff) | |
parent | 909c9942ce927c3dac5f850d9bc110a66a72d397 (diff) | |
download | qtwebkit-37f074e127ba1df465b79664fd4d487fad91a2ce.tar.gz |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I7f624a8e4ba9491c3ec635ffcb66a16c69bf8188
Diffstat (limited to 'Source/JavaScriptCore')
23 files changed, 231 insertions, 61 deletions
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; } |