summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-03-27 14:30:38 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-03-27 14:30:38 +0100
commit37f074e127ba1df465b79664fd4d487fad91a2ce (patch)
tree5819feae97bbc1684fc70d867b843bd04ac8f411 /Source/JavaScriptCore
parent99783e2c7e917224da401ddbd33354c131b3a377 (diff)
parent909c9942ce927c3dac5f850d9bc110a66a72d397 (diff)
downloadqtwebkit-37f074e127ba1df465b79664fd4d487fad91a2ce.tar.gz
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I7f624a8e4ba9491c3ec635ffcb66a16c69bf8188
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/JSCTypedArrayStubs.h5
-rw-r--r--Source/JavaScriptCore/assembler/ARMAssembler.cpp24
-rw-r--r--Source/JavaScriptCore/assembler/ARMAssembler.h20
-rw-r--r--Source/JavaScriptCore/assembler/ARMv7Assembler.h45
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerARM.h11
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h7
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp4
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp32
-rw-r--r--Source/JavaScriptCore/bytecompiler/Label.h6
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp11
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h27
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp25
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp2
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp9
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.cpp20
-rw-r--r--Source/JavaScriptCore/llint/LLIntExceptions.cpp6
-rw-r--r--Source/JavaScriptCore/llint/LLIntSlowPaths.cpp7
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter.cpp11
-rw-r--r--Source/JavaScriptCore/offlineasm/ast.rb2
-rw-r--r--Source/JavaScriptCore/offlineasm/cloop.rb2
-rw-r--r--Source/JavaScriptCore/runtime/JSTypeInfo.h3
-rw-r--r--Source/JavaScriptCore/runtime/Operations.h9
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;
}