Commit 752f7d98 authored by fpizlo@apple.com's avatar fpizlo@apple.com

DFG should speculate more aggressively on obvious cases on

polymorphic get_by_id
https://bugs.webkit.org/show_bug.cgi?id=69235

Reviewed by Oliver Hunt.
        
This implements trivial polymorphic get_by_id. It also fixes
problems in the CSE for CheckStructure in the put_by_id
transition case.
        
Doing this required knowing whether a polymorphic get_by_id stub
was doing a direct access rather than a call of some kind.
        
Slight speed-up on Kraken and SunSpider. 0.5% speed-up in the
scaled mean of all benchmarks.

* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/Instruction.h:
(JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set):
(JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::cellConstant):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::addStructureSet):
(JSC::DFG::Graph::addStructureTransitionData):
* dfg/DFGNode.h:
(JSC::DFG::StructureTransitionData::StructureTransitionData):
(JSC::DFG::Node::hasStructureTransitionData):
(JSC::DFG::Node::structureTransitionData):
(JSC::DFG::Node::hasStructureSet):
(JSC::DFG::Node::structureSet):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::checkStructureLoadElimination):
(JSC::DFG::Propagator::performNodeCSE):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::tryBuildGetByIDProtoList):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureSet.h: Added.
(JSC::DFG::StructureSet::StructureSet):
(JSC::DFG::StructureSet::add):
(JSC::DFG::StructureSet::addAll):
(JSC::DFG::StructureSet::remove):
(JSC::DFG::StructureSet::contains):
(JSC::DFG::StructureSet::isSubsetOf):
(JSC::DFG::StructureSet::isSupersetOf):
(JSC::DFG::StructureSet::size):
(JSC::DFG::StructureSet::at):
(JSC::DFG::StructureSet::operator[]):
(JSC::DFG::StructureSet::last):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC::getPolymorphicAccessStructureListSlot):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@96527 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c1ee1afa
2011-10-02 Filip Pizlo <fpizlo@apple.com>
DFG should speculate more aggressively on obvious cases on
polymorphic get_by_id
https://bugs.webkit.org/show_bug.cgi?id=69235
Reviewed by Oliver Hunt.
This implements trivial polymorphic get_by_id. It also fixes
problems in the CSE for CheckStructure in the put_by_id
transition case.
Doing this required knowing whether a polymorphic get_by_id stub
was doing a direct access rather than a call of some kind.
Slight speed-up on Kraken and SunSpider. 0.5% speed-up in the
scaled mean of all benchmarks.
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/Instruction.h:
(JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set):
(JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::cellConstant):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::addStructureSet):
(JSC::DFG::Graph::addStructureTransitionData):
* dfg/DFGNode.h:
(JSC::DFG::StructureTransitionData::StructureTransitionData):
(JSC::DFG::Node::hasStructureTransitionData):
(JSC::DFG::Node::structureTransitionData):
(JSC::DFG::Node::hasStructureSet):
(JSC::DFG::Node::structureSet):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::checkStructureLoadElimination):
(JSC::DFG::Propagator::performNodeCSE):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::tryBuildGetByIDProtoList):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureSet.h: Added.
(JSC::DFG::StructureSet::StructureSet):
(JSC::DFG::StructureSet::add):
(JSC::DFG::StructureSet::addAll):
(JSC::DFG::StructureSet::remove):
(JSC::DFG::StructureSet::contains):
(JSC::DFG::StructureSet::isSubsetOf):
(JSC::DFG::StructureSet::isSupersetOf):
(JSC::DFG::StructureSet::size):
(JSC::DFG::StructureSet::at):
(JSC::DFG::StructureSet::operator[]):
(JSC::DFG::StructureSet::last):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC::getPolymorphicAccessStructureListSlot):
2011-10-03 Jer Noble <jer.noble@apple.com>
Enable WEB_AUDIO by default in the WebKit/mac port.
......@@ -134,6 +134,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/dfg/DFGScoreBoard.h \
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp \
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h \
Source/JavaScriptCore/dfg/DFGStructureSet.h \
Source/JavaScriptCore/heap/AllocationSpace.cpp \
Source/JavaScriptCore/heap/AllocationSpace.h \
Source/JavaScriptCore/heap/CardSet.h \
......
......@@ -83,6 +83,7 @@
0FD82F4B142806A100179C94 /* BitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82F491428069200179C94 /* BitVector.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FE228ED1436AB2700196C48 /* Heuristics.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Heuristics.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FE228EE1436AB2C00196C48 /* Heuristics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Heuristics.cpp */; };
0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
1400067712A6F7830064D123 /* OSAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400067612A6F7830064D123 /* OSAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
1400069312A6F9E10064D123 /* OSAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */; };
140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; };
......@@ -841,6 +842,7 @@
0FD82F491428069200179C94 /* BitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitVector.h; sourceTree = "<group>"; };
0FE228EA1436AB2300196C48 /* Heuristics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Heuristics.cpp; sourceTree = "<group>"; };
0FE228EB1436AB2300196C48 /* Heuristics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Heuristics.h; sourceTree = "<group>"; };
0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureSet.h; path = dfg/DFGStructureSet.h; sourceTree = "<group>"; };
1400067612A6F7830064D123 /* OSAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSAllocator.h; sourceTree = "<group>"; };
1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAllocatorPosix.cpp; sourceTree = "<group>"; };
140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBasePrivate.h; sourceTree = "<group>"; };
......@@ -2276,6 +2278,7 @@
86EC9DB31328DF44002B2AD7 /* dfg */ = {
isa = PBXGroup;
children = (
0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */,
86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */,
86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */,
0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */,
......@@ -2867,6 +2870,7 @@
0FD52AAE143035A00026DC9F /* UnionFind.h in Headers */,
86880F1E14328BB900B08D42 /* DFGJITCompilerInlineMethods.h in Headers */,
0FE228ED1436AB2700196C48 /* Heuristics.h in Headers */,
0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -58,6 +58,7 @@ namespace JSC {
public:
struct PolymorphicStubInfo {
bool isChain;
bool isDirect;
PolymorphicAccessStructureListStubRoutineType stubRoutine;
WriteBarrier<Structure> base;
union {
......@@ -70,44 +71,47 @@ namespace JSC {
u.proto.clear();
}
void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base)
void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, bool isDirect)
{
stubRoutine = _stubRoutine;
base.set(globalData, owner, _base);
u.proto.clear();
isChain = false;
this->isDirect = isDirect;
}
void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto)
void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto, bool isDirect)
{
stubRoutine = _stubRoutine;
base.set(globalData, owner, _base);
u.proto.set(globalData, owner, _proto);
isChain = false;
this->isDirect = isDirect;
}
void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain)
void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain, bool isDirect)
{
stubRoutine = _stubRoutine;
base.set(globalData, owner, _base);
u.chain.set(globalData, owner, _chain);
isChain = true;
this->isDirect = isDirect;
}
} list[POLYMORPHIC_LIST_CACHE_SIZE];
PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase)
PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, bool isDirect)
{
list[0].set(globalData, owner, stubRoutine, firstBase);
list[0].set(globalData, owner, stubRoutine, firstBase, isDirect);
}
PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto)
PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto, bool isDirect)
{
list[0].set(globalData, owner, stubRoutine, firstBase, firstProto);
list[0].set(globalData, owner, stubRoutine, firstBase, firstProto, isDirect);
}
PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain)
PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain, bool isDirect)
{
list[0].set(globalData, owner, stubRoutine, firstBase, firstChain);
list[0].set(globalData, owner, stubRoutine, firstBase, firstChain, isDirect);
}
void visitAggregate(SlotVisitor& visitor, int count)
......
......@@ -415,6 +415,8 @@ private:
m_constants.append(ConstantRecord());
ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
m_cellConstants.add(cell, m_codeBlock->numberOfConstantRegisters() - 1);
return getJSConstant(m_codeBlock->numberOfConstantRegisters() - 1);
}
......@@ -1160,29 +1162,74 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NodeIndex base = get(currentInstruction[2].u.operand);
unsigned identifierNumber = currentInstruction[3].u.operand;
Identifier identifier = m_codeBlock->identifier(identifierNumber);
StructureStubInfo& stubInfo = m_profiledBlock->getStubInfo(m_currentIndex);
NodeIndex getById = NoNode;
if (stubInfo.seen && stubInfo.accessType == access_get_by_id_self) {
Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
Identifier identifier = m_codeBlock->identifier(identifierNumber);
size_t offset = structure->get(*m_globalData, identifier);
if (offset != notFound) {
addToGraph(CheckStructure, OpInfo(structure), base);
getById = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), addToGraph(GetPropertyStorage, base));
size_t offset = notFound;
StructureSet structureSet;
if (stubInfo.seen) {
switch (stubInfo.accessType) {
case access_get_by_id_self: {
Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
offset = structure->get(*m_globalData, identifier);
StorageAccessData storageAccessData;
storageAccessData.offset = offset;
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
if (offset != notFound)
structureSet.add(structure);
if (offset != notFound)
ASSERT(structureSet.size());
break;
}
case access_get_by_id_self_list: {
PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList;
unsigned size = stubInfo.u.getByIdProtoList.listSize;
for (unsigned i = 0; i < size; ++i) {
if (!list->list[i].isDirect) {
offset = notFound;
break;
}
Structure* structure = list->list[i].base.get();
size_t myOffset = structure->get(*m_globalData, identifier);
if (myOffset == notFound) {
offset = notFound;
break;
}
if (!i)
offset = myOffset;
else if (offset != myOffset) {
offset = notFound;
break;
}
structureSet.add(structure);
}
if (offset != notFound)
ASSERT(structureSet.size());
break;
}
default:
ASSERT(offset == notFound);
break;
}
}
if (getById == NoNode)
getById = addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base);
set(currentInstruction[1].u.operand, getById);
if (offset != notFound) {
ASSERT(structureSet.size());
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), base);
set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), addToGraph(GetPropertyStorage, base)));
StorageAccessData storageAccessData;
storageAccessData.offset = offset;
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
} else
set(currentInstruction[1].u.operand, addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base));
NEXT_OPCODE(op_get_by_id);
}
......@@ -1207,7 +1254,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
size_t offset = structure->get(*m_globalData, identifier);
if (offset != notFound) {
addToGraph(CheckStructure, OpInfo(structure), base);
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), base);
addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
StorageAccessData storageAccessData;
......@@ -1233,17 +1280,17 @@ bool ByteCodeParser::parseBlock(unsigned limit)
size_t offset = newStructure->get(*m_globalData, identifier);
if (offset != notFound) {
addToGraph(CheckStructure, OpInfo(previousStructure), base);
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure)), base);
if (!direct) {
for (WriteBarrier<Structure>* it = structureChain->head(); *it; ++it) {
JSValue prototype = (*it)->storedPrototype();
if (prototype.isNull())
continue;
ASSERT(prototype.isCell());
addToGraph(CheckStructure, OpInfo(prototype.asCell()->structure()), cellConstant(prototype.asCell()));
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), cellConstant(prototype.asCell()));
}
}
addToGraph(PutStructure, OpInfo(newStructure), base);
addToGraph(PutStructure, OpInfo(m_graph.addStructureTransitionData(StructureTransitionData(previousStructure, newStructure))), base);
addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value);
......
......@@ -149,8 +149,14 @@ void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock)
printf("%sid%u", hasPrinted ? ", " : "", node.identifierNumber());
hasPrinted = true;
}
if (node.hasStructure()) {
printf("%sstruct(%p)", hasPrinted ? ", " : "", node.structure());
if (node.hasStructureSet()) {
for (size_t i = 0; i < node.structureSet().size(); ++i) {
printf("%sstruct(%p)", hasPrinted ? ", " : "", node.structureSet()[i]);
hasPrinted = true;
}
}
if (node.hasStructureTransitionData()) {
printf("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure);
hasPrinted = true;
}
if (node.hasStorageAccessData()) {
......
......@@ -329,6 +329,19 @@ public:
#endif
void predictArgumentTypes(ExecState*, CodeBlock*);
StructureSet* addStructureSet(const StructureSet& structureSet)
{
ASSERT(structureSet.size());
m_structureSet.append(structureSet);
return &m_structureSet.last();
}
StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
{
m_structureTransitionData.append(structureTransitionData);
return &m_structureTransitionData.last();
}
Vector< OwnPtr<BasicBlock> , 8> m_blocks;
Vector<NodeIndex, 16> m_varArgChildren;
......@@ -337,6 +350,8 @@ public:
Vector<ResolveGlobalData> m_resolveGlobalData;
Vector<NodeIndex, 8> m_arguments;
SegmentedVector<VariableAccessData, 16> m_variableAccessData;
SegmentedVector<StructureSet, 16> m_structureSet;
SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
unsigned m_preservedVars;
unsigned m_localVars;
unsigned m_parameterSlots;
......
......@@ -26,6 +26,7 @@
#ifndef DFGNode_h
#define DFGNode_h
#include "DFGStructureSet.h"
#include <wtf/BoundsCheckedPointer.h>
#include <wtf/Platform.h>
#include <wtf/UnionFind.h>
......@@ -154,6 +155,19 @@ private:
PredictedType m_prediction;
};
struct StructureTransitionData {
Structure* previousStructure;
Structure* newStructure;
StructureTransitionData() { }
StructureTransitionData(Structure* previousStructure, Structure* newStructure)
: previousStructure(previousStructure)
, newStructure(newStructure)
{
}
};
typedef unsigned ArithNodeFlags;
#define NodeUseBottom 0x00
#define NodeUsedAsNumber 0x01
......@@ -784,14 +798,26 @@ struct Node {
return m_opInfo2;
}
bool hasStructure()
bool hasStructureTransitionData()
{
return op == PutStructure;
}
StructureTransitionData& structureTransitionData()
{
ASSERT(hasStructureTransitionData());
return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
}
bool hasStructureSet()
{
return op == CheckStructure || op == PutStructure;
return op == CheckStructure;
}
Structure* structure()
StructureSet& structureSet()
{
return reinterpret_cast<Structure*>(m_opInfo);
ASSERT(hasStructureSet());
return *reinterpret_cast<StructureSet*>(m_opInfo);
}
bool hasStorageAccessData()
......
......@@ -1013,7 +1013,7 @@ private:
return NoNode;
}
bool checkStructureLoadElimination(Structure* structure, NodeIndex child1)
bool checkStructureLoadElimination(const StructureSet& structureSet, NodeIndex child1)
{
NodeIndex start = startIndexForChildren(child1);
for (NodeIndex index = m_compileIndex; index-- > start;) {
......@@ -1021,15 +1021,17 @@ private:
switch (node.op) {
case CheckStructure:
if (node.child1() == child1
&& node.structure() == structure)
&& structureSet.isSupersetOf(node.structureSet()))
return true;
break;
case PutStructure:
if (node.child1() == child1
&& node.structure() == structure)
&& structureSet.contains(node.structureTransitionData().newStructure))
return true;
return false;
if (structureSet.contains(node.structureTransitionData().previousStructure))
return false;
break;
case PutByOffset:
// Setting a property cannot change the structure.
......@@ -1293,7 +1295,7 @@ private:
break;
case CheckStructure:
if (checkStructureLoadElimination(node.structure(), node.child1()))
if (checkStructureLoadElimination(node.structureSet(), node.child1()))
eliminate();
break;
......
......@@ -347,7 +347,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
if (stubInfo.accessType == access_get_by_id_self) {
ASSERT(!stubInfo.stubRoutine);
polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get());
polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get(), true);
stubInfo.initGetByIdSelfList(polymorphicStructureList, 1);
} else {
polymorphicStructureList = stubInfo.u.getByIdSelfList.structureList;
......@@ -387,7 +387,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
MacroAssemblerCodeRef stubRoutine = patchBuffer.finalizeCode();
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure);
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true);
CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck);
RepatchBuffer repatchBuffer(codeBlock);
......@@ -434,7 +434,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
if (stubInfo.accessType == access_get_by_id_chain) {
ASSERT(!!stubInfo.stubRoutine);
polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get());
polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get(), true);
stubInfo.stubRoutine = MacroAssemblerCodeRef();
stubInfo.initGetByIdProtoList(polymorphicStructureList, 1);
} else {
......@@ -453,7 +453,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), lastProtoBegin, stubRoutine);
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure);
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true);
CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck);
RepatchBuffer repatchBuffer(codeBlock);
......
......@@ -1674,9 +1674,24 @@ void SpeculativeJIT::compile(Node& node)
case CheckStructure: {
SpeculateCellOperand base(this, node.child1());
GPRReg baseGPR = base.gpr();
ASSERT(node.structureSet().size());
speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure())));
if (node.structureSet().size() == 1)
speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structureSet()[0])));
else {
GPRTemporary structure(this);
m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
JITCompiler::JumpList done;
for (size_t i = 0; i < node.structureSet().size() - 1; ++i)
done.append(m_jit.branchPtr(JITCompiler::Equal, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet()[i])));
speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet().last())));
done.link(&m_jit);
}
noResult(m_compileIndex);
break;
......
......@@ -1734,9 +1734,24 @@ void SpeculativeJIT::compile(Node& node)
case CheckStructure: {
SpeculateCellOperand base(this, node.child1());
GPRReg baseGPR = base.gpr();
ASSERT(node.structureSet().size());
speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure())));
if (node.structureSet().size() == 1)
speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structureSet()[0])));
else {
GPRTemporary structure(this);
m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
JITCompiler::JumpList done;
for (size_t i = 0; i < node.structureSet().size() - 1; ++i)
done.append(m_jit.branchPtr(JITCompiler::Equal, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet()[i])));
speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, structure.gpr(), JITCompiler::TrustedImmPtr(node.structureSet().last())));
done.link(&m_jit);
}
noResult(m_compileIndex);
break;
......@@ -1748,10 +1763,10 @@ void SpeculativeJIT::compile(Node& node)
#if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
// Must always emit this write barrier as the structure transition itself requires it
writeBarrier(baseGPR, node.structure(), WriteBarrierForGenericAccess);
writeBarrier(baseGPR, node.structureTransitionData().newStructure, WriteBarrierForGenericAccess);
#endif
m_jit.storePtr(MacroAssembler::TrustedImmPtr(node.structure()), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
m_jit.storePtr(MacroAssembler::TrustedImmPtr(node.structureTransitionData().newStructure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
noResult(m_compileIndex);
break;
......
/*
* Copyright (C) 2011 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 DFGStructureSet_h
#define DFGStructureSet_h
#include <wtf/Vector.h>
namespace JSC {
class Structure;
namespace DFG {
class StructureSet {
public: