Diff
Modified: trunk/LayoutTests/ChangeLog (197832 => 197833)
--- trunk/LayoutTests/ChangeLog 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/LayoutTests/ChangeLog 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,3 +1,21 @@
+2016-03-08 Filip Pizlo <fpi...@apple.com>
+
+ DFG should be able to constant-fold strings
+ https://bugs.webkit.org/show_bug.cgi?id=155200
+
+ Reviewed by Geoffrey Garen.
+
+ * js/regress/script-tests/strcat-const.js: Added.
+ (foo):
+ (bar):
+ * js/regress/script-tests/strcat-length-const.js: Added.
+ (foo):
+ (bar):
+ * js/regress/strcat-const-expected.txt: Added.
+ * js/regress/strcat-const.html: Added.
+ * js/regress/strcat-length-const-expected.txt: Added.
+ * js/regress/strcat-length-const.html: Added.
+
2016-03-08 Joseph Pecoraro <pecor...@apple.com>
Web Inspector: Add Heap domain start/stop tracking commands
Added: trunk/LayoutTests/js/regress/script-tests/strcat-const.js (0 => 197833)
--- trunk/LayoutTests/js/regress/script-tests/strcat-const.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/strcat-const.js 2016-03-09 05:16:47 UTC (rev 197833)
@@ -0,0 +1,16 @@
+function foo(a, b) {
+ return a + b;
+}
+
+function bar() {
+ return foo("hello ", "world!");
+}
+
+noInline(bar);
+
+var result;
+for (var i = 0; i < 1000000; ++i)
+ result = bar();
+
+if (result != "hello world!")
+ throw "Error: bad result: " + result;
Added: trunk/LayoutTests/js/regress/script-tests/strcat-length-const.js (0 => 197833)
--- trunk/LayoutTests/js/regress/script-tests/strcat-length-const.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/strcat-length-const.js 2016-03-09 05:16:47 UTC (rev 197833)
@@ -0,0 +1,16 @@
+function foo(a, b) {
+ return (a + b).length;
+}
+
+function bar() {
+ return foo("hello ", "world!");
+}
+
+noInline(bar);
+
+var result;
+for (var i = 0; i < 1000000; ++i)
+ result = bar();
+
+if (result != "hello world!".length)
+ throw "Error: bad result: " + result;
Added: trunk/LayoutTests/js/regress/strcat-const-expected.txt (0 => 197833)
--- trunk/LayoutTests/js/regress/strcat-const-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/strcat-const-expected.txt 2016-03-09 05:16:47 UTC (rev 197833)
@@ -0,0 +1,10 @@
+JSRegress/strcat-const
+
+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: trunk/LayoutTests/js/regress/strcat-const.html (0 => 197833)
--- trunk/LayoutTests/js/regress/strcat-const.html (rev 0)
+++ trunk/LayoutTests/js/regress/strcat-const.html 2016-03-09 05:16:47 UTC (rev 197833)
@@ -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: trunk/LayoutTests/js/regress/strcat-length-const-expected.txt (0 => 197833)
--- trunk/LayoutTests/js/regress/strcat-length-const-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/strcat-length-const-expected.txt 2016-03-09 05:16:47 UTC (rev 197833)
@@ -0,0 +1,10 @@
+JSRegress/strcat-length-const
+
+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: trunk/LayoutTests/js/regress/strcat-length-const.html (0 => 197833)
--- trunk/LayoutTests/js/regress/strcat-length-const.html (rev 0)
+++ trunk/LayoutTests/js/regress/strcat-length-const.html 2016-03-09 05:16:47 UTC (rev 197833)
@@ -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: trunk/Source/_javascript_Core/ChangeLog (197832 => 197833)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,3 +1,122 @@
+2016-03-08 Filip Pizlo <fpi...@apple.com>
+
+ DFG should be able to constant-fold strings
+ https://bugs.webkit.org/show_bug.cgi?id=155200
+
+ Reviewed by Geoffrey Garen.
+
+ This adds constant-folding of string1 + string2 and string.length. The actual folding
+ rule is easy, but there are some gotchas.
+
+ The problem is that the DFG cannot allocate new JSString objects until we are on the
+ main thread. So, DFG IR must have a node for a JSValue string constant that hasn't been
+ created yet - i.e. it doesn't have any concrete JSValue bits yet.
+
+ We have the ability to speak of such things, using LazyJSValue. But that's a class, not
+ a node type. This patch now adds a node type, LazyJSConstant, which is a Node that holds
+ a LazyJSValue.
+
+ This puts us in a weird situation: AI uses JSValue to represent constants. It would take
+ a lot of work to change it to use LazyJSValue. So, this implements the constant folding
+ in StrengthReductionPhase. I created a bug and put a FIXME about moving these rules into
+ AI.
+
+ OTOH, our experience in B3 shows that constant folding in strength reduction is quite
+ nice. It would totally make sense to have strength reduction have constant folding rules
+ that mirror the rules in AI, or to factor out the AI constant folding rules, the same
+ way that B3 factors out those rules into Value methods.
+
+ Another issue is how to represent the cumulative result of possibly many foldings. I
+ initially considered adding LazyJSValue kinds that represented concatenation. Folding
+ the concatenation to a constant meand that this constant was actually a LazyJSValue that
+ represented the concatenation of two other things. But this would get super messy if we
+ wanted to fold an operation that uses the results of another folded operation.
+
+ So, the JIT thread folds string operations by creating a WTF::String that contains the
+ result. The DFG::Graph holds a +1 on the underlying StringImpl, so we can pass the
+ StringImpl* around without reference counting. The LazyJSValue now has a special kind
+ that means: we created this StringImpl* on the JIT thread, and once the JIT is done, we
+ will relinquish ownership of it. LazyJSValue has some magic to emit code for these
+ to-be-created-JSStrings while also transferring ownership of the StringImpl from the JIT
+ thread to the main thread and registering the JSString with the GC.
+
+ This just implements folding for concatenation and GetArrayLength. It's just a proof of
+ concept for evil things I want to do later.
+
+ This change is a 2.5x speed-up on the string concatenation microbenchmarks I added in
+ this patch.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGFrozenValue.cpp:
+ (JSC::DFG::FrozenValue::emptySingleton):
+ (JSC::DFG::FrozenValue::tryGetString):
+ (JSC::DFG::FrozenValue::dumpInContext):
+ * dfg/DFGFrozenValue.h:
+ (JSC::DFG::FrozenValue::strength):
+ * dfg/DFGGraph.h:
+ * dfg/DFGLazyJSValue.cpp:
+ (JSC::DFG::LazyJSValue::newString):
+ (JSC::DFG::LazyJSValue::getValue):
+ (JSC::DFG::equalToStringImpl):
+ (JSC::DFG::LazyJSValue::tryGetStringImpl):
+ (JSC::DFG::LazyJSValue::tryGetString):
+ (JSC::DFG::LazyJSValue::strictEqual):
+ (JSC::DFG::LazyJSValue::switchLookupValue):
+ (JSC::DFG::LazyJSValue::emit):
+ (JSC::DFG::LazyJSValue::dumpInContext):
+ * dfg/DFGLazyJSValue.h:
+ (JSC::DFG::LazyJSValue::LazyJSValue):
+ (JSC::DFG::LazyJSValue::knownStringImpl):
+ (JSC::DFG::LazyJSValue::kind):
+ (JSC::DFG::LazyJSValue::tryGetValue):
+ (JSC::DFG::LazyJSValue::character):
+ (JSC::DFG::LazyJSValue::stringImpl):
+ * dfg/DFGMayExit.cpp:
+ (JSC::DFG::mayExit):
+ * dfg/DFGNode.cpp:
+ (JSC::DFG::Node::convertToIdentityOn):
+ (JSC::DFG::Node::convertToLazyJSConstant):
+ (JSC::DFG::Node::convertToPutHint):
+ (JSC::DFG::Node::convertToPutClosureVarHint):
+ (JSC::DFG::Node::tryGetString):
+ (JSC::DFG::Node::promotedLocationDescriptor):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToConstant):
+ (JSC::DFG::Node::convertToConstantStoragePointer):
+ (JSC::DFG::Node::castConstant):
+ (JSC::DFG::Node::hasLazyJSValue):
+ (JSC::DFG::Node::lazyJSValue):
+ (JSC::DFG::Node::initializationValueForActivation):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex):
+ (JSC::DFG::SpeculativeJIT::compileLazyJSConstant):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGStrengthReductionPhase.cpp:
+ (JSC::DFG::StrengthReductionPhase::handleNode):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileInt52Constant):
+ (JSC::FTL::DFG::LowerDFGToB3::compileLazyJSConstant):
+ (JSC::FTL::DFG::LowerDFGToB3::compileDoubleRep):
+
2016-03-08 Joseph Pecoraro <pecor...@apple.com>
Web Inspector: Memory Timeline should show MemoryPressure events
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -141,6 +141,21 @@
setBuiltInConstant(node, *node->constant());
break;
}
+
+ case LazyJSConstant: {
+ LazyJSValue value = node->lazyJSValue();
+ switch (value.kind()) {
+ case LazyJSValue::KnownValue:
+ setConstant(node, value.value()->value());
+ break;
+ case LazyJSValue::SingleCharacterString:
+ case LazyJSValue::KnownStringImpl:
+ case LazyJSValue::NewStringImpl:
+ forNode(node).setType(m_graph, SpecString);
+ break;
+ }
+ break;
+ }
case Identity: {
forNode(node) = forNode(node->child1());
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -113,7 +113,7 @@
case Int52Constant:
def(PureValue(node, node->constant()));
return;
-
+
case Identity:
case Phantom:
case Check:
@@ -121,6 +121,11 @@
case CheckStructureImmediate:
return;
+ case LazyJSConstant:
+ // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
+ // more bits than we currently have in PureValue.
+ return;
+
case ArithIMul:
case ArithAbs:
case ArithClz32:
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -47,6 +47,7 @@
case JSConstant:
case DoubleConstant:
case Int52Constant:
+ case LazyJSConstant:
case Identity:
case GetCallee:
case GetArgumentCount:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1451,6 +1451,7 @@
// Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
case SetArgument:
case JSConstant:
+ case LazyJSConstant:
case DoubleConstant:
case GetLocal:
case GetCallee:
Modified: trunk/Source/_javascript_Core/dfg/DFGFrozenValue.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGFrozenValue.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGFrozenValue.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
#if ENABLE(DFG_JIT)
+#include "DFGLazyJSValue.h"
#include "JSCInlines.h"
namespace JSC { namespace DFG {
@@ -38,6 +39,11 @@
return ∅
}
+String FrozenValue::tryGetString(Graph& graph)
+{
+ return LazyJSValue(this).tryGetString(graph);
+}
+
void FrozenValue::dumpInContext(PrintStream& out, DumpContext* context) const
{
if (!!m_value && m_value.isCell())
Modified: trunk/Source/_javascript_Core/dfg/DFGFrozenValue.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGFrozenValue.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGFrozenValue.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -93,6 +93,8 @@
// The strength of the value itself. The structure is almost always weak.
ValueStrength strength() const { return m_strength; }
+
+ String tryGetString(Graph&);
void dumpInContext(PrintStream& out, DumpContext* context) const;
void dump(PrintStream& out) const;
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -868,6 +868,7 @@
Bag<CallVarargsData> m_callVarargsData;
Bag<LoadVarargsData> m_loadVarargsData;
Bag<StackAccessData> m_stackAccessData;
+ Bag<LazyJSValue> m_lazyJSValues;
Vector<InlineVariableData, 4> m_inlineVariableData;
HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness;
HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>> m_bytecodeKills;
@@ -880,6 +881,9 @@
unsigned m_localVars;
unsigned m_nextMachineLocal;
unsigned m_parameterSlots;
+
+ HashSet<String> m_localStrings;
+ HashMap<const StringImpl*, String> m_copiedStrings;
#if USE(JSVALUE32_64)
std::unordered_map<int64_t, double*> m_doubleConstantsMap;
Modified: trunk/Source/_javascript_Core/dfg/DFGJITFinalizer.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGJITFinalizer.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGJITFinalizer.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -82,6 +82,10 @@
void JITFinalizer::finalizeCommon()
{
+ // Some JIT finalizers may have added more constants. Shrink-to-fit those things now.
+ m_plan.codeBlock->constants().shrinkToFit();
+ m_plan.codeBlock->constantsSourceCodeRepresentation().shrinkToFit();
+
#if ENABLE(FTL_JIT)
m_jitCode->optimizeAfterWarmUp(m_plan.codeBlock);
#endif // ENABLE(FTL_JIT)
Modified: trunk/Source/_javascript_Core/dfg/DFGLazyJSValue.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGLazyJSValue.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGLazyJSValue.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,10 +28,21 @@
#if ENABLE(DFG_JIT)
+#include "CCallHelpers.h"
+#include "DFGGraph.h"
#include "JSCInlines.h"
+#include "LinkBuffer.h"
namespace JSC { namespace DFG {
+LazyJSValue LazyJSValue::newString(Graph& graph, const String& string)
+{
+ LazyJSValue result;
+ result.m_kind = NewStringImpl;
+ result.u.stringImpl = graph.m_localStrings.add(string).iterator->impl();
+ return result;
+}
+
JSValue LazyJSValue::getValue(VM& vm) const
{
switch (m_kind) {
@@ -40,6 +51,7 @@
case SingleCharacterString:
return jsSingleCharacterString(&vm, u.character);
case KnownStringImpl:
+ case NewStringImpl:
return jsString(&vm, u.stringImpl);
}
RELEASE_ASSERT_NOT_REACHED();
@@ -75,6 +87,48 @@
return triState(WTF::equal(stringImpl, string));
}
+const StringImpl* LazyJSValue::tryGetStringImpl() const
+{
+ switch (m_kind) {
+ case KnownStringImpl:
+ case NewStringImpl:
+ return u.stringImpl;
+
+ case KnownValue:
+ if (JSString* string = jsDynamicCast<JSString*>(value()->value()))
+ return string->tryGetValueImpl();
+ return nullptr;
+
+ default:
+ return nullptr;
+ }
+}
+
+String LazyJSValue::tryGetString(Graph& graph) const
+{
+ switch (m_kind) {
+ case NewStringImpl:
+ return u.stringImpl;
+
+ case SingleCharacterString:
+ return String(&u.character, 1);
+
+ default:
+ if (const StringImpl* string = tryGetStringImpl()) {
+ unsigned ginormousStringLength = 10000;
+ if (string->length() > ginormousStringLength)
+ return String();
+
+ auto result = graph.m_copiedStrings.add(string, String());
+ if (result.isNewEntry)
+ result.iterator->value = string->isolatedCopy();
+ return result.iterator->value;
+ }
+
+ return String();
+ }
+}
+
TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
{
switch (m_kind) {
@@ -85,6 +139,7 @@
case SingleCharacterString:
return equalToSingleCharacter(value()->value(), other.character());
case KnownStringImpl:
+ case NewStringImpl:
return equalToStringImpl(value()->value(), other.stringImpl());
}
break;
@@ -93,6 +148,7 @@
case SingleCharacterString:
return triState(character() == other.character());
case KnownStringImpl:
+ case NewStringImpl:
if (other.stringImpl()->length() != 1)
return FalseTriState;
return triState(other.stringImpl()->at(0) == character());
@@ -101,8 +157,10 @@
}
break;
case KnownStringImpl:
+ case NewStringImpl:
switch (other.m_kind) {
case KnownStringImpl:
+ case NewStringImpl:
return triState(WTF::equal(stringImpl(), other.stringImpl()));
default:
return other.strictEqual(*this);
@@ -143,6 +201,45 @@
}
}
+void LazyJSValue::emit(CCallHelpers& jit, JSValueRegs result) const
+{
+ if (m_kind == KnownValue) {
+ jit.moveValue(value()->value(), result);
+ return;
+ }
+
+ // It must be some kind of cell.
+#if USE(JSVALUE32_64)
+ jit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), result.tagGPR());
+#endif
+ CCallHelpers::DataLabelPtr label = jit.moveWithPatch(
+ CCallHelpers::TrustedImmPtr(static_cast<size_t>(0xd1e7beeflu)),
+ result.payloadGPR());
+
+ LazyJSValue thisValue = *this;
+
+ // Once we do this, we're committed. Otherwise we leak memory. Note that we call ref/deref
+ // manually to ensure that there is no concurrency shadiness. We are doing something here
+ // that might be rather brutal: transfering ownership of this string.
+ if (m_kind == NewStringImpl)
+ thisValue.u.stringImpl->ref();
+
+ CodeBlock* codeBlock = jit.codeBlock();
+
+ jit.addLinkTask(
+ [codeBlock, label, thisValue] (LinkBuffer& linkBuffer) {
+ JSValue realValue = thisValue.getValue(linkBuffer.vm());
+ RELEASE_ASSERT(realValue.isCell());
+
+ codeBlock->addConstant(realValue);
+
+ if (thisValue.m_kind == NewStringImpl)
+ thisValue.u.stringImpl->deref();
+
+ linkBuffer.patch(label, realValue.asCell());
+ });
+}
+
void LazyJSValue::dumpInContext(PrintStream& out, DumpContext* context) const
{
switch (m_kind) {
@@ -155,8 +252,11 @@
out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1), ")");
return;
case KnownStringImpl:
- out.print("Lazy:String(", stringImpl(), ")");
+ out.print("Lazy:KnownString(", stringImpl(), ")");
return;
+ case NewStringImpl:
+ out.print("Lazy:NewString(", stringImpl(), ")");
+ return;
}
RELEASE_ASSERT_NOT_REACHED();
}
Modified: trunk/Source/_javascript_Core/dfg/DFGLazyJSValue.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGLazyJSValue.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGLazyJSValue.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,19 +32,26 @@
#include "DFGFrozenValue.h"
#include <wtf/text/StringImpl.h>
-namespace JSC { namespace DFG {
+namespace JSC {
+class CCallHelpers;
+
+namespace DFG {
+
+class Graph;
+
// Represents either a JSValue, or for JSValues that require allocation in the heap,
// it tells you everything you'd need to know in order to allocate it.
-enum LazinessKind {
- KnownValue,
- SingleCharacterString,
- KnownStringImpl
-};
-
class LazyJSValue {
public:
+ enum LazinessKind {
+ KnownValue,
+ SingleCharacterString,
+ KnownStringImpl,
+ NewStringImpl
+ };
+
LazyJSValue(FrozenValue* value = FrozenValue::emptySingleton())
: m_kind(KnownValue)
{
@@ -66,6 +73,10 @@
result.u.stringImpl = string;
return result;
}
+
+ static LazyJSValue newString(Graph&, const String&);
+
+ LazinessKind kind() const { return m_kind; }
FrozenValue* tryGetValue(Graph&) const
{
@@ -87,16 +98,22 @@
ASSERT(m_kind == SingleCharacterString);
return u.character;
}
+
+ const StringImpl* tryGetStringImpl() const;
+ String tryGetString(Graph&) const;
+
StringImpl* stringImpl() const
{
- ASSERT(m_kind == KnownStringImpl);
+ ASSERT(m_kind == KnownStringImpl || m_kind == NewStringImpl);
return u.stringImpl;
}
-
+
TriState strictEqual(const LazyJSValue& other) const;
uintptr_t switchLookupValue(SwitchKind) const;
+
+ void emit(CCallHelpers&, JSValueRegs) const;
void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -92,6 +92,7 @@
case SetArgument:
case JSConstant:
case DoubleConstant:
+ case LazyJSConstant:
case Int52Constant:
case MovHint:
case SetLocal:
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGNode.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -160,6 +160,14 @@
}
}
+void Node::convertToLazyJSConstant(Graph& graph, LazyJSValue value)
+{
+ m_op = LazyJSConstant;
+ m_flags &= ~NodeMustGenerate;
+ m_opInfo = bitwise_cast<uintptr_t>(graph.m_lazyJSValues.add(value));
+ children.reset();
+}
+
void Node::convertToPutHint(const PromotedLocationDescriptor& descriptor, Node* base, Node* value)
{
m_op = PutHint;
@@ -193,6 +201,15 @@
child1().node(), child2().node());
}
+String Node::tryGetString(Graph& graph)
+{
+ if (hasConstant())
+ return constant()->tryGetString(graph);
+ if (hasLazyJSValue())
+ return lazyJSValue().tryGetString(graph);
+ return String();
+}
+
PromotedLocationDescriptor Node::promotedLocationDescriptor()
{
return PromotedLocationDescriptor(static_cast<PromotedLocationKind>(m_opInfo), m_opInfo2);
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -494,6 +494,8 @@
m_opInfo = bitwise_cast<uintptr_t>(value);
children.reset();
}
+
+ void convertToLazyJSConstant(Graph&, LazyJSValue);
void convertToConstantStoragePointer(void* pointer)
{
@@ -743,6 +745,19 @@
return result;
}
+ bool hasLazyJSValue()
+ {
+ return op() == LazyJSConstant;
+ }
+
+ LazyJSValue lazyJSValue()
+ {
+ ASSERT(hasLazyJSValue());
+ return *bitwise_cast<LazyJSValue*>(m_opInfo);
+ }
+
+ String tryGetString(Graph&);
+
JSValue initializationValueForActivation() const
{
ASSERT(op() == CreateActivation);
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -41,6 +41,9 @@
macro(DoubleConstant, NodeResultDouble) \
macro(Int52Constant, NodeResultInt52) \
\
+ /* Lazy JSValue constant. We don't know the JSValue bits of it yet. */\
+ macro(LazyJSConstant, NodeResultJS) \
+ \
/* Marker to indicate that an operation was optimized entirely and all that is left */\
/* is to make one node alias another. CSE will later usually eliminate this node, */\
/* though it may choose not to if it would corrupt predictions (very rare). */\
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -668,7 +668,8 @@
case StoreBarrier:
case GetStack:
case GetRegExpObjectLastIndex:
- case SetRegExpObjectLastIndex: {
+ case SetRegExpObjectLastIndex:
+ case LazyJSConstant: {
// This node should never be visible at this stage of compilation. It is
// inserted by fixup(), which follows this phase.
DFG_CRASH(m_graph, node, "Unexpected node during prediction propagation");
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -137,6 +137,7 @@
case JSConstant:
case DoubleConstant:
case Int52Constant:
+ case LazyJSConstant:
case Identity:
case ToThis:
case CreateThis:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -7647,6 +7647,14 @@
noResult(node);
}
+void SpeculativeJIT::compileLazyJSConstant(Node* node)
+{
+ JSValueRegsTemporary result(this);
+ JSValueRegs resultRegs = result.regs();
+ node->lazyJSValue().emit(m_jit, resultRegs);
+ jsValueResult(resultRegs, node);
+}
+
} } // namespace JSC::DFG
#endif
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -2400,6 +2400,7 @@
void compilePutAccessorByVal(Node*);
void compileGetRegExpObjectLastIndex(Node*);
void compileSetRegExpObjectLastIndex(Node*);
+ void compileLazyJSConstant(Node*);
void moveTrueTo(GPRReg);
void moveFalseTo(GPRReg);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1874,6 +1874,10 @@
initConstantInfo(node);
break;
+ case LazyJSConstant:
+ compileLazyJSConstant(node);
+ break;
+
case Identity: {
speculate(node, node->child1());
switch (node->child1().useKind()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1982,6 +1982,10 @@
initConstantInfo(node);
break;
+ case LazyJSConstant:
+ compileLazyJSConstant(node);
+ break;
+
case Identity: {
speculate(node, node->child1());
switch (node->child1().useKind()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -291,7 +291,51 @@
break;
}
-
+
+ // FIXME: We have a lot of string constant-folding rules here. It would be great to
+ // move these to the abstract interpreter once AbstractValue can support LazyJSValue.
+ // https://bugs.webkit.org/show_bug.cgi?id=155204
+
+ case MakeRope:
+ case ValueAdd:
+ case StrCat: {
+ String leftString = m_node->child1()->tryGetString(m_graph);
+ if (!leftString)
+ break;
+ String rightString = m_node->child2()->tryGetString(m_graph);
+ if (!rightString)
+ break;
+ String extraString;
+ if (m_node->child3()) {
+ extraString = m_node->child3()->tryGetString(m_graph);
+ if (!extraString)
+ break;
+ }
+
+ StringBuilder builder;
+ builder.append(leftString);
+ builder.append(rightString);
+ if (!!extraString)
+ builder.append(extraString);
+
+ m_node->convertToLazyJSConstant(
+ m_graph, LazyJSValue::newString(m_graph, builder.toString()));
+ m_changed = true;
+ break;
+ }
+
+ case GetArrayLength: {
+ if (m_node->arrayMode().type() == Array::Generic
+ || m_node->arrayMode().type() == Array::String) {
+ String string = m_node->child1()->tryGetString(m_graph);
+ if (!!string) {
+ m_graph.convertToConstant(m_node, jsNumber(string.length()));
+ m_changed = true;
+ }
+ }
+ break;
+ }
+
default:
break;
}
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -44,6 +44,7 @@
switch (node->op()) {
case JSConstant:
+ case LazyJSConstant:
case GetLocal:
case SetLocal:
case PutStack:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (197832 => 197833)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-03-09 05:16:47 UTC (rev 197833)
@@ -446,6 +446,9 @@
case Int52Constant:
compileInt52Constant();
break;
+ case LazyJSConstant:
+ compileLazyJSConstant();
+ break;
case DoubleRep:
compileDoubleRep();
break;
@@ -1044,6 +1047,18 @@
setStrictInt52(m_out.constInt64(value));
}
+ void compileLazyJSConstant()
+ {
+ PatchpointValue* patchpoint = m_out.patchpoint(Int64);
+ LazyJSValue value = m_node->lazyJSValue();
+ patchpoint->setGenerator(
+ [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ value.emit(jit, JSValueRegs(params[0].gpr()));
+ });
+ patchpoint->effects = Effects::none();
+ setJSValue(patchpoint);
+ }
+
void compileDoubleRep()
{
switch (m_node->child1().useKind()) {
Modified: trunk/Source/WTF/ChangeLog (197832 => 197833)
--- trunk/Source/WTF/ChangeLog 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/WTF/ChangeLog 2016-03-09 05:16:47 UTC (rev 197833)
@@ -1,3 +1,17 @@
+2016-03-08 Filip Pizlo <fpi...@apple.com>
+
+ DFG should be able to constant-fold strings
+ https://bugs.webkit.org/show_bug.cgi?id=155200
+
+ Reviewed by Geoffrey Garen.
+
+ Also disable assertions about reference counting strings on the JIT thread. We will do
+ that now and it's OK.
+
+ * wtf/text/StringImpl.h:
+ (WTF::StringImpl::ref):
+ (WTF::StringImpl::deref):
+
2016-03-08 Anders Carlsson <ander...@apple.com>
Fix AppKitCompatibilityDeclarations build.
Modified: trunk/Source/WTF/wtf/text/StringImpl.h (197832 => 197833)
--- trunk/Source/WTF/wtf/text/StringImpl.h 2016-03-09 05:02:15 UTC (rev 197832)
+++ trunk/Source/WTF/wtf/text/StringImpl.h 2016-03-09 05:16:47 UTC (rev 197833)
@@ -585,7 +585,7 @@
inline void ref()
{
- ASSERT(!isCompilationThread());
+ ASSERT(!isCompilationThread() || !isAtomic());
STRING_STATS_REF_STRING(*this);
@@ -594,7 +594,7 @@
inline void deref()
{
- ASSERT(!isCompilationThread());
+ ASSERT(!isCompilationThread() || !isAtomic());
STRING_STATS_DEREF_STRING(*this);