]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - bytecompiler/StaticPropertyAnalyzer.h
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / bytecompiler / StaticPropertyAnalyzer.h
diff --git a/bytecompiler/StaticPropertyAnalyzer.h b/bytecompiler/StaticPropertyAnalyzer.h
new file mode 100644 (file)
index 0000000..dd7f0ab
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef StaticPropertyAnalyzer_h
+#define StaticPropertyAnalyzer_h
+
+#include "StaticPropertyAnalysis.h"
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+// Used for flow-insensitive static analysis of the number of properties assigned to an object.
+// We use this analysis with other runtime data to produce an optimization guess. This analysis
+// is understood to be lossy, and it's OK if it turns out to be wrong sometimes.
+class StaticPropertyAnalyzer {
+public:
+    StaticPropertyAnalyzer(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>*);
+
+    void createThis(int dst, unsigned offsetOfInlineCapacityOperand);
+    void newObject(int dst, unsigned offsetOfInlineCapacityOperand);
+    void putById(int dst, unsigned propertyIndex); // propertyIndex is an index into a uniqued set of strings.
+    void mov(int dst, int src);
+
+    void kill();
+    void kill(int dst);
+
+private:
+    void kill(StaticPropertyAnalysis*);
+
+    Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* m_instructions;
+    typedef HashMap<int, RefPtr<StaticPropertyAnalysis>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int> > AnalysisMap;
+    AnalysisMap m_analyses;
+};
+
+inline StaticPropertyAnalyzer::StaticPropertyAnalyzer(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* instructions)
+    : m_instructions(instructions)
+{
+}
+
+inline void StaticPropertyAnalyzer::createThis(int dst, unsigned offsetOfInlineCapacityOperand)
+{
+    AnalysisMap::AddResult addResult = m_analyses.add(
+        dst, StaticPropertyAnalysis::create(m_instructions, offsetOfInlineCapacityOperand));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry); // Can't have two 'this' in the same constructor.
+}
+
+inline void StaticPropertyAnalyzer::newObject(int dst, unsigned offsetOfInlineCapacityOperand)
+{
+    RefPtr<StaticPropertyAnalysis> analysis = StaticPropertyAnalysis::create(m_instructions, offsetOfInlineCapacityOperand);
+    AnalysisMap::AddResult addResult = m_analyses.add(dst, analysis);
+    if (!addResult.isNewEntry) {
+        kill(addResult.iterator->value.get());
+        addResult.iterator->value = analysis.release();
+    }
+}
+
+inline void StaticPropertyAnalyzer::putById(int dst, unsigned propertyIndex)
+{
+    StaticPropertyAnalysis* analysis = m_analyses.get(dst);
+    if (!analysis)
+        return;
+    analysis->addPropertyIndex(propertyIndex);
+}
+
+inline void StaticPropertyAnalyzer::mov(int dst, int src)
+{
+    RefPtr<StaticPropertyAnalysis> analysis = m_analyses.get(src);
+    if (!analysis) {
+        kill(dst);
+        return;
+    }
+
+    AnalysisMap::AddResult addResult = m_analyses.add(dst, analysis);
+    if (!addResult.isNewEntry) {
+        kill(addResult.iterator->value.get());
+        addResult.iterator->value = analysis.release();
+    }
+}
+
+inline void StaticPropertyAnalyzer::kill(StaticPropertyAnalysis* analysis)
+{
+    if (!analysis)
+        return;
+    if (!analysis->hasOneRef()) // Aliases for this object still exist, so it might acquire more properties.
+        return;
+    analysis->record();
+}
+
+inline void StaticPropertyAnalyzer::kill(int dst)
+{
+    // We observe kills in order to avoid piling on properties to an object after
+    // its bytecode register has been recycled.
+
+    // Consider these cases:
+
+    // (1) Aliased temporary
+    // var o1 = { name: name };
+    // var o2 = { name: name };
+
+    // (2) Aliased local -- no control flow
+    // var local;
+    // local = new Object;
+    // local.name = name;
+    // ...
+
+    // local = lookup();
+    // local.didLookup = true;
+    // ...
+
+    // (3) Aliased local -- control flow
+    // var local;
+    // if (condition)
+    //     local = { };
+    // else {
+    //     local = new Object;
+    // }
+    // local.name = name;
+
+    // (Note: our default codegen for "new Object" looks like case (3).)
+
+    // Case (1) is easy because temporaries almost never survive across control flow.
+
+    // Cases (2) and (3) are hard. Case (2) should kill "local", while case (3) should
+    // not. There is no great way to solve these cases with simple static analysis.
+
+    // Since this is a simple static analysis, we just try to catch the simplest cases,
+    // so we accept kills to any registers except for registers that have no inferred
+    // properties yet.
+
+    AnalysisMap::iterator it = m_analyses.find(dst);
+    if (it == m_analyses.end())
+        return;
+    if (!it->value->propertyIndexCount())
+        return;
+
+    kill(it->value.get());
+    m_analyses.remove(it);
+}
+
+inline void StaticPropertyAnalyzer::kill()
+{
+    while (m_analyses.size())
+        kill(m_analyses.take(m_analyses.begin()->key).get());
+}
+
+} // namespace JSC
+
+#endif // StaticPropertyAnalyzer_h