FTL should do polymorphic PutById inlining
https://bugs.webkit.org/show_bug.cgi?id=129210
Source/JavaScriptCore:
Reviewed by Mark Hahnenberg and Oliver Hunt.
This makes PutByIdStatus inform us about polymorphic cases by returning an array of
PutByIdVariants. The DFG now has a node called MultiPutByOffset that indicates a
selection of multiple inlined PutByIdVariants.
MultiPutByOffset is almost identical to MultiGetByOffset, which we added in
http://trac.webkit.org/changeset/164207.
This also does some FTL refactoring to make MultiPutByOffset share code with some nodes
that generate similar code.
1% speed-up on V8v7 due to splay improving by 6.8%. Splay does the thing where it
sometimes swaps field insertion order, creating fake polymorphism.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):
(JSC::PutByIdStatus::computeForStubInfo):
(JSC::PutByIdStatus::dump):
* bytecode/PutByIdStatus.h:
(JSC::PutByIdStatus::PutByIdStatus):
(JSC::PutByIdStatus::isSimple):
(JSC::PutByIdStatus::numVariants):
(JSC::PutByIdStatus::variants):
(JSC::PutByIdStatus::at):
(JSC::PutByIdStatus::operator[]):
* bytecode/PutByIdVariant.cpp: Added.
(JSC::PutByIdVariant::dump):
(JSC::PutByIdVariant::dumpInContext):
* bytecode/PutByIdVariant.h: Added.
(JSC::PutByIdVariant::PutByIdVariant):
(JSC::PutByIdVariant::replace):
(JSC::PutByIdVariant::transition):
(JSC::PutByIdVariant::kind):
(JSC::PutByIdVariant::isSet):
(JSC::PutByIdVariant::operator!):
(JSC::PutByIdVariant::structure):
(JSC::PutByIdVariant::oldStructure):
(JSC::PutByIdVariant::newStructure):
(JSC::PutByIdVariant::structureChain):
(JSC::PutByIdVariant::offset):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::emitPrototypeChecks):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::emitPutById):
(JSC::DFG::ByteCodeParser::handlePutById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::checkStructureElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::putStructureStoreElimination):
(JSC::DFG::CSEPhase::getByOffsetLoadElimination):
(JSC::DFG::CSEPhase::putByOffsetStoreElimination):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
* dfg/DFGNode.cpp:
(JSC::DFG::MultiPutByOffsetData::writesStructures):
(JSC::DFG::MultiPutByOffsetData::reallocatesStorage):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPutByOffset):
(JSC::DFG::Node::hasMultiPutByOffsetData):
(JSC::DFG::Node::multiPutByOffsetData):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compilePutStructure):
(JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compilePutByOffset):
(JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
(JSC::FTL::LowerDFGToLLVM::loadProperty):
(JSC::FTL::LowerDFGToLLVM::storeProperty):
(JSC::FTL::LowerDFGToLLVM::addressOfProperty):
(JSC::FTL::LowerDFGToLLVM::storageForTransition):
(JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::emitStoreBarrier):
* tests/stress/fold-multi-put-by-offset-to-put-by-offset.js: Added.
* tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js: Added.
* tests/stress/multi-put-by-offset-reallocation-cases.js: Added.
LayoutTests:
Reviewed by Mark Hahnenberg and Oliver Hunt.
Add a microbenchmark for polymorphic PutById.
* js/regress/polymorphic-put-by-id-expected.txt: Added.
* js/regress/polymorphic-put-by-id.html: Added.
* js/regress/script-tests/polymorphic-put-by-id.js: Added.
(foo):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@164620 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
index b1e1538..a06fb1e 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
@@ -30,8 +30,10 @@
#include "LLIntData.h"
#include "LowLevelInterpreter.h"
#include "JSCInlines.h"
+#include "PolymorphicPutByIdList.h"
#include "Structure.h"
#include "StructureChain.h"
+#include <wtf/ListDump.h>
namespace JSC {
@@ -56,15 +58,15 @@
Structure* structure = instruction[4].u.structure.get();
if (!structure)
- return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(NoInformation);
if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id)
|| instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_out_of_line)) {
PropertyOffset offset = structure->getConcurrently(*profiledBlock->vm(), uid);
if (!isValidOffset(offset))
- return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(NoInformation);
- return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
+ return PutByIdVariant::replace(structure, offset);
}
ASSERT(structure->transitionWatchpointSetHasBeenInvalidated());
@@ -81,14 +83,14 @@
PropertyOffset offset = newStructure->getConcurrently(*profiledBlock->vm(), uid);
if (!isValidOffset(offset))
- return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(NoInformation);
- return PutByIdStatus(
- SimpleTransition, structure, newStructure,
+ return PutByIdVariant::transition(
+ structure, newStructure,
chain ? adoptRef(new IntendedStructureChain(profiledBlock, structure, chain)) : 0,
offset);
#else
- return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(NoInformation);
#endif
}
@@ -102,7 +104,7 @@
#if ENABLE(DFG_JIT)
if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex)
|| hasExitSite(locker, profiledBlock, bytecodeIndex))
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(TakesSlowPath);
StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex));
PutByIdStatus result = computeForStubInfo(locker, profiledBlock, stubInfo, uid);
@@ -112,7 +114,7 @@
return result;
#else // ENABLE(JIT)
UNUSED_PARAM(map);
- return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(NoInformation);
#endif // ENABLE(JIT)
}
@@ -123,25 +125,22 @@
return PutByIdStatus();
if (stubInfo->resetByGC)
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(TakesSlowPath);
switch (stubInfo->accessType) {
case access_unset:
// If the JIT saw it but didn't optimize it, then assume that this takes slow path.
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(TakesSlowPath);
case access_put_by_id_replace: {
PropertyOffset offset =
stubInfo->u.putByIdReplace.baseObjectStructure->getConcurrently(
*profiledBlock->vm(), uid);
if (isValidOffset(offset)) {
- return PutByIdStatus(
- SimpleReplace,
- stubInfo->u.putByIdReplace.baseObjectStructure.get(),
- 0, 0,
- offset);
+ return PutByIdVariant::replace(
+ stubInfo->u.putByIdReplace.baseObjectStructure.get(), offset);
}
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(TakesSlowPath);
}
case access_put_by_id_transition_normal:
@@ -151,8 +150,7 @@
stubInfo->u.putByIdTransition.structure->getConcurrently(
*profiledBlock->vm(), uid);
if (isValidOffset(offset)) {
- return PutByIdStatus(
- SimpleTransition,
+ return PutByIdVariant::transition(
stubInfo->u.putByIdTransition.previousStructure.get(),
stubInfo->u.putByIdTransition.structure.get(),
stubInfo->u.putByIdTransition.chain ? adoptRef(new IntendedStructureChain(
@@ -160,13 +158,51 @@
stubInfo->u.putByIdTransition.chain.get())) : 0,
offset);
}
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(TakesSlowPath);
+ }
+
+ case access_put_by_id_list: {
+ PolymorphicPutByIdList* list = stubInfo->u.putByIdList.list;
+
+ PutByIdStatus result;
+ result.m_state = Simple;
+
+ for (unsigned i = 0; i < list->size(); ++i) {
+ const PutByIdAccess& access = list->at(i);
+
+ switch (access.type()) {
+ case PutByIdAccess::Replace: {
+ Structure* structure = access.structure();
+ PropertyOffset offset = structure->getConcurrently(*profiledBlock->vm(), uid);
+ if (!isValidOffset(offset))
+ return PutByIdStatus(TakesSlowPath);
+ result.m_variants.append(PutByIdVariant::replace(structure, offset));
+ break;
+ }
+
+ case PutByIdAccess::Transition: {
+ PropertyOffset offset =
+ access.newStructure()->getConcurrently(*profiledBlock->vm(), uid);
+ if (!isValidOffset(offset))
+ return PutByIdStatus(TakesSlowPath);
+ result.m_variants.append(PutByIdVariant::transition(
+ access.oldStructure(), access.newStructure(),
+ access.chain() ? adoptRef(new IntendedStructureChain(
+ profiledBlock, access.oldStructure(), access.chain())) : 0,
+ offset));
+ break;
+ }
+
+ default:
+ return PutByIdStatus(TakesSlowPath);
+ }
+ }
+
+ return result;
}
default:
- // FIXME: We should handle polymorphic PutById. We probably have some interesting things
- // we could do about it.
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
+ return PutByIdStatus(TakesSlowPath);
}
}
#endif
@@ -223,7 +259,7 @@
// the specialized slot.
return PutByIdStatus(TakesSlowPath);
}
- return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
+ return PutByIdVariant::replace(structure, offset);
}
// Our hypothesis is that we're doing a transition. Before we prove that this is really
@@ -276,7 +312,26 @@
ASSERT(!transition->transitionDidInvolveSpecificValue());
ASSERT(isValidOffset(offset));
- return PutByIdStatus(SimpleTransition, structure, transition, chain.release(), offset);
+ return PutByIdVariant::transition(structure, transition, chain.release(), offset);
+}
+
+void PutByIdStatus::dump(PrintStream& out) const
+{
+ switch (m_state) {
+ case NoInformation:
+ out.print("(NoInformation)");
+ return;
+
+ case Simple:
+ out.print("(", listDump(m_variants), ")");
+ return;
+
+ case TakesSlowPath:
+ out.print("(TakesSlowPath)");
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
index 1684a74..4bb8b98 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.h
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,8 +27,7 @@
#define PutByIdStatus_h
#include "ExitingJITType.h"
-#include "IntendedStructureChain.h"
-#include "PropertyOffset.h"
+#include "PutByIdVariant.h"
#include "StructureStubInfo.h"
#include <wtf/text/StringImpl.h>
@@ -45,51 +44,27 @@
enum State {
// It's uncached so we have no information.
NoInformation,
- // It's cached as a direct store into an object property for cases where the object
- // already has the property.
- SimpleReplace,
- // It's cached as a transition from one structure that lacks the property to one that
- // includes the property, and a direct store to this new property.
- SimpleTransition,
+ // It's cached as a simple store of some kind.
+ Simple,
// It's known to often take slow path.
TakesSlowPath
};
PutByIdStatus()
: m_state(NoInformation)
- , m_oldStructure(0)
- , m_newStructure(0)
- , m_structureChain(0)
- , m_offset(invalidOffset)
{
}
explicit PutByIdStatus(State state)
: m_state(state)
- , m_oldStructure(0)
- , m_newStructure(0)
- , m_structureChain(0)
- , m_offset(invalidOffset)
{
ASSERT(m_state == NoInformation || m_state == TakesSlowPath);
}
- PutByIdStatus(
- State state,
- Structure* oldStructure,
- Structure* newStructure,
- PassRefPtr<IntendedStructureChain> structureChain,
- PropertyOffset offset)
- : m_state(state)
- , m_oldStructure(oldStructure)
- , m_newStructure(newStructure)
- , m_structureChain(structureChain)
- , m_offset(offset)
+ PutByIdStatus(const PutByIdVariant& variant)
+ : m_state(Simple)
{
- ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == !m_oldStructure);
- ASSERT((m_state != SimpleTransition) == !m_newStructure);
- ASSERT(!((m_state != SimpleTransition) && m_structureChain));
- ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == (m_offset == invalidOffset));
+ m_variants.append(variant);
}
static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, StringImpl* uid);
@@ -101,14 +76,15 @@
bool isSet() const { return m_state != NoInformation; }
bool operator!() const { return m_state == NoInformation; }
- bool isSimpleReplace() const { return m_state == SimpleReplace; }
- bool isSimpleTransition() const { return m_state == SimpleTransition; }
+ bool isSimple() const { return m_state == Simple; }
bool takesSlowPath() const { return m_state == TakesSlowPath; }
- Structure* oldStructure() const { return m_oldStructure; }
- Structure* newStructure() const { return m_newStructure; }
- IntendedStructureChain* structureChain() const { return m_structureChain.get(); }
- PropertyOffset offset() const { return m_offset; }
+ size_t numVariants() const { return m_variants.size(); }
+ const Vector<PutByIdVariant, 1>& variants() const { return m_variants; }
+ const PutByIdVariant& at(size_t index) const { return m_variants[index]; }
+ const PutByIdVariant& operator[](size_t index) const { return at(index); }
+
+ void dump(PrintStream&) const;
private:
#if ENABLE(DFG_JIT)
@@ -120,10 +96,7 @@
static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid);
State m_state;
- Structure* m_oldStructure;
- Structure* m_newStructure;
- RefPtr<IntendedStructureChain> m_structureChain;
- PropertyOffset m_offset;
+ Vector<PutByIdVariant, 1> m_variants;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp b/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp
new file mode 100644
index 0000000..f83c102
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "config.h"
+#include "PutByIdVariant.h"
+
+namespace JSC {
+
+void PutByIdVariant::dump(PrintStream& out) const
+{
+ dumpInContext(out, 0);
+}
+
+void PutByIdVariant::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+ switch (kind()) {
+ case NotSet:
+ out.print("<empty>");
+ return;
+
+ case Replace:
+ out.print(
+ "<Replace: ", pointerDumpInContext(structure(), context), ", ", offset(), ">");
+ return;
+
+ case Transition:
+ out.print(
+ "<Transition: ", pointerDumpInContext(oldStructure(), context), " -> ",
+ pointerDumpInContext(newStructure(), context), ", ",
+ pointerDumpInContext(structureChain(), context), ", ", offset(), ">");
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/PutByIdVariant.h b/Source/JavaScriptCore/bytecode/PutByIdVariant.h
new file mode 100644
index 0000000..eba95e8
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/PutByIdVariant.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 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 PutByIdVariant_h
+#define PutByIdVariant_h
+
+#include "IntendedStructureChain.h"
+#include "PropertyOffset.h"
+
+namespace JSC {
+
+class PutByIdVariant {
+public:
+ enum Kind {
+ NotSet,
+ Replace,
+ Transition
+ };
+
+ PutByIdVariant()
+ : m_kind(NotSet)
+ , m_oldStructure(0)
+ , m_newStructure(0)
+ , m_offset(invalidOffset)
+ {
+ }
+
+ static PutByIdVariant replace(Structure* structure, PropertyOffset offset)
+ {
+ PutByIdVariant result;
+ result.m_kind = Replace;
+ result.m_oldStructure = structure;
+ result.m_offset = offset;
+ return result;
+ }
+
+ static PutByIdVariant transition(
+ Structure* oldStructure, Structure* newStructure,
+ PassRefPtr<IntendedStructureChain> structureChain, PropertyOffset offset)
+ {
+ PutByIdVariant result;
+ result.m_kind = Transition;
+ result.m_oldStructure = oldStructure;
+ result.m_newStructure = newStructure;
+ result.m_structureChain = structureChain;
+ result.m_offset = offset;
+ return result;
+ }
+
+ Kind kind() const { return m_kind; }
+
+ bool isSet() const { return kind() != NotSet; }
+ bool operator!() const { return !isSet(); }
+
+ Structure* structure() const
+ {
+ ASSERT(kind() == Replace);
+ return m_oldStructure;
+ }
+
+ Structure* oldStructure() const
+ {
+ ASSERT(kind() == Transition || kind() == Replace);
+ return m_oldStructure;
+ }
+
+ Structure* newStructure() const
+ {
+ ASSERT(kind() == Transition);
+ return m_newStructure;
+ }
+
+ IntendedStructureChain* structureChain() const
+ {
+ ASSERT(kind() == Transition);
+ return m_structureChain.get();
+ }
+
+ PropertyOffset offset() const
+ {
+ ASSERT(isSet());
+ return m_offset;
+ }
+
+ void dump(PrintStream&) const;
+ void dumpInContext(PrintStream&, DumpContext*) const;
+
+private:
+ Kind m_kind;
+ Structure* m_oldStructure;
+ Structure* m_newStructure;
+ RefPtr<IntendedStructureChain> m_structureChain;
+ PropertyOffset m_offset;
+};
+
+} // namespace JSC
+
+#endif // PutByIdVariant_h
+