fourthTier: Structure should be able to tell you if it's valid to load at a given offset from any object with that structure
https://bugs.webkit.org/show_bug.cgi?id=118878

Reviewed by Oliver Hunt.

- Change Structure::isValidOffset() to actually answer the question "If I attempted
  to load from an object of this structure, at this offset, would I commit suicide
  or would I get back some kind of value?"

- Change StorageAccessData::offset to use a PropertyOffset. It should have been that
  way from the start.

- Fix PutStructure so that it sets haveStructures in all of the cases that it should.

- Make GetByOffset also reference the base object in addition to the butterfly.

The future use of this power will be to answer questions like "If I hoisted this
GetByOffset or PutByOffset to this point, would it cause crashes, or would it be
fine?"

I don't currently plan to use this power to perform validation, since the CSE has
the power to eliminate CheckStructure's that the CFA wouldn't be smart enough to
remove - both in the case of StructureSets where size >= 2 and in the case of
CheckStructures that match across PutStructures. At first I tried to write a
validator that was aware of this, but the validation code got way too complicated
and I started having nightmares of spurious assertion bugs being filed against me.

This also changes some of the code for how we hash FunctionExecutable's for debug
dumps, since that code still had some thread-safety issues. Basically, the
concurrent JIT needs to use the CodeBlock's precomputed hash and never call anything
that could transitively try to compute the hash from the source code. The source
code is a string that may be lazily computed, and that involves all manner of thread
unsafe things.

* bytecode/CodeOrigin.cpp:
(JSC::InlineCallFrame::hash):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::handlePutByOffset):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCFAPhase.cpp:
(JSC::DFG::CFAPhase::performBlockCFA):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.h:
(StorageAccessData):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToGetByOffset):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compilePutByOffset):
* runtime/FunctionExecutableDump.cpp:
(JSC::FunctionExecutableDump::dump):
* runtime/Structure.h:
(Structure):
(JSC::Structure::isValidOffset):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153284 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index a25d277..2a36dda 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,68 @@
+2013-07-19  Filip Pizlo  <fpizlo@apple.com>
+
+        fourthTier: Structure should be able to tell you if it's valid to load at a given offset from any object with that structure
+        https://bugs.webkit.org/show_bug.cgi?id=118878
+
+        Reviewed by Oliver Hunt.
+        
+        - Change Structure::isValidOffset() to actually answer the question "If I attempted
+          to load from an object of this structure, at this offset, would I commit suicide
+          or would I get back some kind of value?"
+        
+        - Change StorageAccessData::offset to use a PropertyOffset. It should have been that
+          way from the start.
+        
+        - Fix PutStructure so that it sets haveStructures in all of the cases that it should.
+        
+        - Make GetByOffset also reference the base object in addition to the butterfly.
+        
+        The future use of this power will be to answer questions like "If I hoisted this
+        GetByOffset or PutByOffset to this point, would it cause crashes, or would it be
+        fine?"
+        
+        I don't currently plan to use this power to perform validation, since the CSE has
+        the power to eliminate CheckStructure's that the CFA wouldn't be smart enough to
+        remove - both in the case of StructureSets where size >= 2 and in the case of
+        CheckStructures that match across PutStructures. At first I tried to write a
+        validator that was aware of this, but the validation code got way too complicated
+        and I started having nightmares of spurious assertion bugs being filed against me.
+        
+        This also changes some of the code for how we hash FunctionExecutable's for debug
+        dumps, since that code still had some thread-safety issues. Basically, the
+        concurrent JIT needs to use the CodeBlock's precomputed hash and never call anything
+        that could transitively try to compute the hash from the source code. The source
+        code is a string that may be lazily computed, and that involves all manner of thread
+        unsafe things.
+
+        * bytecode/CodeOrigin.cpp:
+        (JSC::InlineCallFrame::hash):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleGetByOffset):
+        (JSC::DFG::ByteCodeParser::handlePutByOffset):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCFAPhase.cpp:
+        (JSC::DFG::CFAPhase::performBlockCFA):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.h:
+        (StorageAccessData):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToGetByOffset):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
+        (JSC::FTL::LowerDFGToLLVM::compilePutByOffset):
+        * runtime/FunctionExecutableDump.cpp:
+        (JSC::FunctionExecutableDump::dump):
+        * runtime/Structure.h:
+        (Structure):
+        (JSC::Structure::isValidOffset):
+
 2013-07-18  Filip Pizlo  <fpizlo@apple.com>
 
         fourthTier: AbstractInterpreter should explicitly ask AbstractState to create new AbstractValues for newly born nodes
diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.cpp b/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
index cdf1466..0150113 100644
--- a/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
@@ -84,7 +84,8 @@
 
 CodeBlockHash InlineCallFrame::hash() const
 {
-    return executable->hashFor(specializationKind());
+    return jsCast<FunctionExecutable*>(executable.get())->generatedBytecodeFor(
+        specializationKind()).hash();
 }
 
 CString InlineCallFrame::inferredName() const
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index c8c38f7..3f98598 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -1256,6 +1256,7 @@
         }
 
         node->setCanExit(true);
+        m_state.setHaveStructures(true);
 
         // If this structure check is attempting to prove knowledge already held in
         // the futurePossibleStructure set then the constant folding phase should
@@ -1268,7 +1269,6 @@
         }
 
         filter(value, set);
-        m_state.setHaveStructures(true);
         break;
     }
         
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index abb1b8a..2eac9e8 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1624,14 +1624,10 @@
         propertyStorage = base;
     else
         propertyStorage = addToGraph(GetButterfly, base);
-    // FIXME: It would be far more efficient for load elimination (and safer from
-    // an OSR standpoint) if GetByOffset also referenced the object we were loading
-    // from, and if we could load eliminate a GetByOffset even if the butterfly
-    // had changed. That would be a great success.
-    Node* getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage);
+    Node* getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base);
 
     StorageAccessData storageAccessData;
-    storageAccessData.offset = indexRelativeToBase(offset);
+    storageAccessData.offset = offset;
     storageAccessData.identifierNumber = identifierNumber;
     m_graph.m_storageAccessData.append(storageAccessData);
 
@@ -1655,7 +1651,7 @@
     Node* result = addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, base, value);
     
     StorageAccessData storageAccessData;
-    storageAccessData.offset = indexRelativeToBase(offset);
+    storageAccessData.offset = offset;
     storageAccessData.identifierNumber = identifier;
     m_graph.m_storageAccessData.append(storageAccessData);
 
@@ -2456,7 +2452,7 @@
                     value);
                 
                 StorageAccessData storageAccessData;
-                storageAccessData.offset = indexRelativeToBase(putByIdStatus.offset());
+                storageAccessData.offset = putByIdStatus.offset();
                 storageAccessData.identifierNumber = identifierNumber;
                 m_graph.m_storageAccessData.append(storageAccessData);
             } else {
diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
index 9a392d4..693d1ed 100644
--- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
@@ -100,6 +100,8 @@
                 Node* node = block->at(i);
                 dataLogF("      %s @%u: ", Graph::opName(node->op()), node->index());
                 m_interpreter.dump(WTF::dataFile());
+                if (m_state.haveStructures())
+                    dataLog(" (Have Structures)");
                 dataLogF("\n");
             }
             if (!m_interpreter.execute(i)) {
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index e1d911a..d211e97 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -207,7 +207,7 @@
                 node->convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
                 
                 StorageAccessData storageAccessData;
-                storageAccessData.offset = indexRelativeToBase(status.offset());
+                storageAccessData.offset = status.offset();
                 storageAccessData.identifierNumber = identifierNumber;
                 m_graph.m_storageAccessData.append(storageAccessData);
                 break;
@@ -318,7 +318,7 @@
                 node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
                 
                 StorageAccessData storageAccessData;
-                storageAccessData.offset = indexRelativeToBase(status.offset());
+                storageAccessData.offset = status.offset();
                 storageAccessData.identifierNumber = identifierNumber;
                 m_graph.m_storageAccessData.append(storageAccessData);
                 break;
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index ffb26d2..2a24483 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -820,6 +820,7 @@
         case GetByOffset: {
             if (!node->child1()->hasStorageResult())
                 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
+            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child2());
             break;
         }
             
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 389ff45..f818a22 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -56,7 +56,7 @@
 namespace DFG {
 
 struct StorageAccessData {
-    size_t offset;
+    PropertyOffset offset;
     unsigned identifierNumber;
 };
 
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 57a09aa..2e7a966 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -410,6 +410,8 @@
     {
         ASSERT(m_op == GetById || m_op == GetByIdFlush);
         m_opInfo = storageAccessDataIndex;
+        children.setChild2(children.child1());
+        children.child2().setUseKind(KnownCellUse);
         children.setChild1(storage);
         m_op = GetByOffset;
         m_flags &= ~NodeClobbersWorld;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 5f00a89..bf0ce50 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4009,7 +4009,7 @@
         
         StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()];
         
-        m_jit.load64(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue)), resultGPR);
+        m_jit.load64(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)), resultGPR);
         
         jsValueResult(resultGPR, node);
         break;
@@ -4031,7 +4031,7 @@
 
         StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()];
         
-        m_jit.store64(valueGPR, JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue)));
+        m_jit.store64(valueGPR, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)));
         
         noResult(node);
         break;
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index c7d011f..880915d 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -1351,7 +1351,7 @@
                 m_out.address(
                     m_heaps.properties[data.identifierNumber],
                     lowStorage(m_node->child1()),
-                    data.offset * sizeof(EncodedJSValue))));
+                    offsetRelativeToBase(data.offset))));
     }
     
     void compilePutByOffset()
@@ -1364,7 +1364,7 @@
             m_out.address(
                 m_heaps.properties[data.identifierNumber],
                 lowStorage(m_node->child1()),
-                data.offset * sizeof(EncodedJSValue)));
+                offsetRelativeToBase(data.offset)));
     }
     
     void compileGetGlobalVar()
diff --git a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp
index 1577ed5..a885272 100644
--- a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp
@@ -26,11 +26,23 @@
 #include "config.h"
 #include "FunctionExecutableDump.h"
 
+#include "CodeBlock.h"
+
 namespace JSC {
 
 void FunctionExecutableDump::dump(PrintStream& out) const
 {
-    out.print(m_executable->inferredName().string(), "#", m_executable->hashFor(CodeForCall), "/", m_executable->hashFor(CodeForConstruct), ":[", RawPointer(m_executable), "]");
+    out.print(m_executable->inferredName().string(), "#");
+    if (m_executable->isGeneratedForCall())
+        out.print(m_executable->generatedBytecodeForCall().hash());
+    else
+        out.print("<nogen>");
+    out.print("/");
+    if (m_executable->isGeneratedForConstruct())
+        out.print(m_executable->generatedBytecodeForConstruct().hash());
+    else
+        out.print("<nogen>");
+    out.print(":[", RawPointer(m_executable), "]");
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 03170f7..5a67c2a 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -220,20 +220,11 @@
         return outOfLineCapacity() + inlineCapacity();
     }
 
-    PropertyOffset firstValidOffset() const
-    {
-        if (hasInlineStorage())
-            return 0;
-        return firstOutOfLineOffset;
-    }
-    PropertyOffset lastValidOffset() const
-    {
-        return m_offset;
-    }
     bool isValidOffset(PropertyOffset offset) const
     {
-        return offset >= firstValidOffset()
-            && offset <= lastValidOffset();
+        return JSC::isValidOffset(offset)
+            && (offset < m_inlineCapacity
+                || (offset >= firstOutOfLineOffset && offset <= m_offset));
     }
 
     bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);