Diff
Modified: branches/dfgFourthTier/LayoutTests/ChangeLog (151884 => 151885)
--- branches/dfgFourthTier/LayoutTests/ChangeLog 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/LayoutTests/ChangeLog 2013-06-23 04:57:11 UTC (rev 151885)
@@ -1,5 +1,24 @@
2013-06-21 Filip Pizlo <[email protected]>
+ fourthTier: DFG shouldn't exit just because a String GetByVal went out-of-bounds
+ https://bugs.webkit.org/show_bug.cgi?id=117906
+
+ Reviewed by Mark Hahnenberg.
+
+ The out-of-bounds benchmark that isn't insane speeds up by 22x in this
+ patch.
+
+ * fast/js/regress/script-tests/string-get-by-val-out-of-bounds-insane.js: Added.
+ (foo):
+ * fast/js/regress/script-tests/string-get-by-val-out-of-bounds.js: Added.
+ (foo):
+ * fast/js/regress/string-get-by-val-out-of-bounds-expected.txt: Added.
+ * fast/js/regress/string-get-by-val-out-of-bounds-insane-expected.txt: Added.
+ * fast/js/regress/string-get-by-val-out-of-bounds-insane.html: Added.
+ * fast/js/regress/string-get-by-val-out-of-bounds.html: Added.
+
+2013-06-21 Filip Pizlo <[email protected]>
+
fourthTier: DFG should CSE MakeRope
https://bugs.webkit.org/show_bug.cgi?id=117905
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-get-by-val-out-of-bounds-insane.js (0 => 151885)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-get-by-val-out-of-bounds-insane.js (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-get-by-val-out-of-bounds-insane.js 2013-06-23 04:57:11 UTC (rev 151885)
@@ -0,0 +1,14 @@
+function foo(string) {
+ var result = ["", ""];
+ for (var i = 0; i < 100000; ++i)
+ result[i & 1] = string[i & 1];
+ return result;
+}
+
+Object.prototype[1] = 42;
+
+var result = foo("x");
+if (result[0] != "x")
+ throw "Bad result[0]: " + result[0];
+if (result[1] != 42)
+ throw "Bad result[1]: " + result[1];
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-get-by-val-out-of-bounds.js (0 => 151885)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-get-by-val-out-of-bounds.js (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-get-by-val-out-of-bounds.js 2013-06-23 04:57:11 UTC (rev 151885)
@@ -0,0 +1,12 @@
+function foo(string) {
+ var result = ["", ""];
+ for (var i = 0; i < 1000000; ++i)
+ result[i & 1] = string[i & 1];
+ return result;
+}
+
+var result = foo("x");
+if (result[0] != "x")
+ throw "Bad result[0]: " + result[0];
+if (typeof result[1] != "undefined")
+ throw "Bad result[1]: " + result[1];
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-expected.txt (0 => 151885)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-expected.txt (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-expected.txt 2013-06-23 04:57:11 UTC (rev 151885)
@@ -0,0 +1,10 @@
+JSRegress/string-get-by-val-out-of-bounds
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-insane-expected.txt (0 => 151885)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-insane-expected.txt (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-insane-expected.txt 2013-06-23 04:57:11 UTC (rev 151885)
@@ -0,0 +1,10 @@
+JSRegress/string-get-by-val-out-of-bounds-insane
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-insane.html (0 => 151885)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-insane.html (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds-insane.html 2013-06-23 04:57:11 UTC (rev 151885)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds.html (0 => 151885)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds.html (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-get-by-val-out-of-bounds.html 2013-06-23 04:57:11 UTC (rev 151885)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Modified: branches/dfgFourthTier/Source/_javascript_Core/ChangeLog (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/ChangeLog 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/ChangeLog 2013-06-23 04:57:11 UTC (rev 151885)
@@ -1,5 +1,35 @@
2013-06-22 Filip Pizlo <[email protected]>
+ fourthTier: DFG shouldn't exit just because a String GetByVal went out-of-bounds
+ https://bugs.webkit.org/show_bug.cgi?id=117906
+
+ Reviewed by Mark Hahnenberg.
+
+ This does the obvious thing, but also makes sure that out-of-bounds accesses
+ don't fall off into a C call, but try to do the fast thing if the prototype
+ chain is sane. We ought to probably do this for other array accesses in the
+ future, as well, since it's so darn easy.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::executeEffects):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::objectPrototypeIsSane):
+ (JSC):
+ (JSC::JSGlobalObject::arrayPrototypeChainIsSane):
+ (JSC::JSGlobalObject::stringPrototypeChainIsSane):
+ * runtime/JSGlobalObject.h:
+ (JSGlobalObject):
+
+2013-06-22 Filip Pizlo <[email protected]>
+
fourthTier: GC's put_by_id transition fixpoint should converge more quickly
https://bugs.webkit.org/show_bug.cgi?id=117912
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGAbstractState.cpp (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2013-06-23 04:57:11 UTC (rev 151885)
@@ -889,7 +889,19 @@
forNode(node).makeTop();
break;
case Array::String:
- forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
+ if (node->arrayMode().isOutOfBounds()) {
+ // If the watchpoint was still valid we could totally set this to be
+ // SpecString | SpecOther. Except that we'd have to be careful. If we
+ // tested the watchpoint state here then it could change by the time
+ // we got to the backend. So to do this right, we'd have to get the
+ // fixup phase to check the watchpoint state and then bake into the
+ // GetByVal operation the fact that we're using a watchpoint, using
+ // something like Array::SaneChain (except not quite, because that
+ // implies an in-bounds access). None of this feels like it's worth it,
+ // so we're going with TOP for now.
+ forNode(node).makeTop();
+ } else
+ forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
break;
case Array::Arguments:
forNode(node).makeTop();
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2013-06-23 04:57:11 UTC (rev 151885)
@@ -367,13 +367,25 @@
blessArrayOperation(node->child1(), node->child2(), node->child3());
ArrayMode arrayMode = node->arrayMode();
- if (arrayMode.type() == Array::Double
- && arrayMode.arrayClass() == Array::OriginalArray
- && arrayMode.speculation() == Array::InBounds
- && arrayMode.conversion() == Array::AsIs
- && m_graph.globalObjectFor(node->codeOrigin)->arrayPrototypeChainIsSane()
- && !(node->flags() & NodeUsedAsOther))
- node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+ switch (arrayMode.type()) {
+ case Array::Double:
+ if (arrayMode.arrayClass() == Array::OriginalArray
+ && arrayMode.speculation() == Array::InBounds
+ && arrayMode.conversion() == Array::AsIs
+ && m_graph.globalObjectFor(node->codeOrigin)->arrayPrototypeChainIsSane()
+ && !(node->flags() & NodeUsedAsOther))
+ node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+ break;
+
+ case Array::String:
+ if ((node->prediction() & ~SpecString)
+ || m_graph.hasExitSite(node->codeOrigin, OutOfBounds))
+ node->setArrayMode(arrayMode.withSpeculation(Array::OutOfBounds));
+ break;
+
+ default:
+ break;
+ }
switch (node->arrayMode().type()) {
case Array::SelectUsingPredictions:
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGOperations.cpp (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGOperations.cpp 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGOperations.cpp 2013-06-23 04:57:11 UTC (rev 151885)
@@ -471,7 +471,7 @@
return JSValue::encode(JSValue(base).get(exec, ident));
}
-EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
+ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
@@ -485,6 +485,16 @@
return JSValue::encode(JSValue(base).get(exec, index));
}
+EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
+{
+ return getByValCellInt(exec, base, index);
+}
+
+EncodedJSValue DFG_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index)
+{
+ return getByValCellInt(exec, base, index);
+}
+
EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, StringImpl* uid)
{
VM* vm = &exec->vm();
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGOperations.h (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGOperations.h 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGOperations.h 2013-06-23 04:57:11 UTC (rev 151885)
@@ -69,6 +69,7 @@
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, StringImpl*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJssZ)(ExecState*, JSString*, int32_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EP)(ExecState*, void*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, void*);
@@ -132,6 +133,7 @@
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState*, JSArray*, int32_t) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationGetByValStringInt(ExecState*, JSString*, int32_t) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, StringImpl*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, StringImpl*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, StringImpl*) WTF_INTERNAL;
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-06-23 04:57:11 UTC (rev 151885)
@@ -2042,14 +2042,39 @@
GPRReg propertyReg = property.gpr();
GPRReg storageReg = storage.gpr();
+ GPRTemporary scratch(this);
+ GPRReg scratchReg = scratch.gpr();
+#if USE(JSVALUE32_64)
+ GPRTemporary resultTag;
+ GPRReg resultTagReg = InvalidGPRReg;
+ if (node->arrayMode().isOutOfBounds()) {
+ GPRTemporary realResultTag(this);
+ resultTag.adopt(realResultTag);
+ resultTagReg = resultTag.gpr();
+ }
+#endif
+
+ if (node->arrayMode().isOutOfBounds()) {
+ JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
+ if (globalObject->stringPrototypeChainIsSane()) {
+ m_jit.addLazily(
+ speculationWatchpoint(),
+ globalObject->stringPrototype()->structure()->transitionWatchpointSet());
+ m_jit.addLazily(
+ speculationWatchpoint(),
+ globalObject->objectPrototype()->structure()->transitionWatchpointSet());
+ }
+ }
+
ASSERT(ArrayMode(Array::String).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
// unsigned comparison so we can filter out negative indices and indices that are too large
- speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
+ JITCompiler::Jump outOfBounds = m_jit.branch32(
+ MacroAssembler::AboveOrEqual, propertyReg,
+ MacroAssembler::Address(baseReg, JSString::offsetOfLength()));
+ if (node->arrayMode().isInBounds())
+ speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
- GPRTemporary scratch(this);
- GPRReg scratchReg = scratch.gpr();
-
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
// Load the character into scratchReg
@@ -2077,7 +2102,46 @@
slowPathCall(
bigCharacter, this, operationSingleCharacterString, scratchReg, scratchReg));
- cellResult(scratchReg, m_currentNode);
+ if (node->arrayMode().isOutOfBounds()) {
+#if USE(JSVALUE32_64)
+ m_jit.move(TrustedImm32(JSValue::CellTag), resultTagReg);
+#endif
+
+ JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
+ if (globalObject->stringPrototypeChainIsSane()) {
+#if USE(JSVALUE64)
+ addSlowPathGenerator(
+ slowPathMove(
+ outOfBounds, this, TrustedImm64(JSValue::encode(jsUndefined())),
+ scratchReg));
+#else
+ addSlowPathGenerator(
+ slowPathMove(
+ outOfBounds, this,
+ TrustedImm32(JSValue::UndefinedTag), resultTagReg,
+ TrustedImm32(0), scratchReg));
+#endif
+ } else {
+#if USE(JSVALUE64)
+ addSlowPathGenerator(
+ slowPathCall(
+ outOfBounds, this, operationGetByValStringInt,
+ scratchReg, baseReg, propertyReg));
+#else
+ addSlowPathGenerator(
+ slowPathCall(
+ outOfBounds, this, operationGetByValStringInt,
+ resultTagReg, scratchReg, baseReg, propertyReg));
+#endif
+ }
+
+#if USE(JSVALUE64)
+ jsValueResult(scratchReg, m_currentNode);
+#else
+ jsValueResult(resultTagReg, scratchReg, m_currentNode);
+#endif
+ } else
+ cellResult(scratchReg, m_currentNode);
}
GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(Node* node)
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2013-06-23 04:57:11 UTC (rev 151885)
@@ -1155,6 +1155,11 @@
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EJssZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg result, void* pointer, size_t size)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
@@ -1375,6 +1380,11 @@
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EJssZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg resultTag, GPRReg resultPayload, void* pointer, size_t size)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
Modified: branches/dfgFourthTier/Source/_javascript_Core/runtime/JSGlobalObject.cpp (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2013-06-23 04:57:11 UTC (rev 151885)
@@ -437,14 +437,26 @@
}
}
+bool JSGlobalObject::objectPrototypeIsSane()
+{
+ return !hasIndexedProperties(m_objectPrototype->structure()->indexingType())
+ && m_objectPrototype->prototype().isNull();
+}
+
bool JSGlobalObject::arrayPrototypeChainIsSane()
{
return !hasIndexedProperties(m_arrayPrototype->structure()->indexingType())
&& m_arrayPrototype->prototype() == m_objectPrototype.get()
- && !hasIndexedProperties(m_objectPrototype->structure()->indexingType())
- && m_objectPrototype->prototype().isNull();
+ && objectPrototypeIsSane();
}
+bool JSGlobalObject::stringPrototypeChainIsSane()
+{
+ return !hasIndexedProperties(m_stringPrototype->structure()->indexingType())
+ && m_stringPrototype->prototype() == m_objectPrototype.get()
+ && objectPrototypeIsSane();
+}
+
void JSGlobalObject::createThrowTypeError(ExecState* exec)
{
JSFunction* thrower = JSFunction::create(exec, this, 0, String(), globalFuncThrowTypeError);
Modified: branches/dfgFourthTier/Source/_javascript_Core/runtime/JSGlobalObject.h (151884 => 151885)
--- branches/dfgFourthTier/Source/_javascript_Core/runtime/JSGlobalObject.h 2013-06-23 03:31:43 UTC (rev 151884)
+++ branches/dfgFourthTier/Source/_javascript_Core/runtime/JSGlobalObject.h 2013-06-23 04:57:11 UTC (rev 151885)
@@ -341,7 +341,9 @@
void haveABadTime(VM&);
+ bool objectPrototypeIsSane();
bool arrayPrototypeChainIsSane();
+ bool stringPrototypeChainIsSane();
void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
unsigned profileGroup() const