Commit 0402d951 authored by oliver@apple.com's avatar oliver@apple.com

fourthTier: Structure should be able to tell you if it's valid to load at a...

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
parent 02e7a979
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
......
......@@ -84,7 +84,8 @@ JSFunction* InlineCallFrame::calleeForCallFrame(ExecState* exec) const
CodeBlockHash InlineCallFrame::hash() const
{
return executable->hashFor(specializationKind());
return jsCast<FunctionExecutable*>(executable.get())->generatedBytecodeFor(
specializationKind()).hash();
}
CString InlineCallFrame::inferredName() const
......
......@@ -1256,6 +1256,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned indexInBloc
}
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 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned indexInBloc
}
filter(value, set);
m_state.setHaveStructures(true);
break;
}
......
......@@ -1624,14 +1624,10 @@ Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, u
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* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, Propert
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 @@ bool ByteCodeParser::parseBlock(unsigned limit)
value);
StorageAccessData storageAccessData;
storageAccessData.offset = indexRelativeToBase(putByIdStatus.offset());
storageAccessData.offset = putByIdStatus.offset();
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
} else {
......
......@@ -100,6 +100,8 @@ private:
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)) {
......
......@@ -207,7 +207,7 @@ private:
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 @@ private:
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;
......
......@@ -820,6 +820,7 @@ private:
case GetByOffset: {
if (!node->child1()->hasStorageResult())
setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child2());
break;
}
......
......@@ -56,7 +56,7 @@ class ExecState;
namespace DFG {
struct StorageAccessData {
size_t offset;
PropertyOffset offset;
unsigned identifierNumber;
};
......
......@@ -410,6 +410,8 @@ struct Node {
{
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;
......
......@@ -4009,7 +4009,7 @@ void SpeculativeJIT::compile(Node* node)
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 @@ void SpeculativeJIT::compile(Node* node)
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;
......
......@@ -1351,7 +1351,7 @@ private:
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 @@ private:
m_out.address(
m_heaps.properties[data.identifierNumber],
lowStorage(m_node->child1()),
data.offset * sizeof(EncodedJSValue)));
offsetRelativeToBase(data.offset)));
}
void compileGetGlobalVar()
......
......@@ -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
......
......@@ -220,20 +220,11 @@ public:
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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment