<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[170855] branches/ftlopt</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/170855">170855</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-07-07 13:39:36 -0700 (Mon, 07 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ftlopt] Infer immutable object properties
https://bugs.webkit.org/show_bug.cgi?id=134567

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore: 
        
This introduces a new way of inferring immutable object properties. A property is said to
be immutable if after its creation (i.e. the transition that creates it), we never
overwrite it (i.e. replace it) or delete it. Immutability is a property of an &quot;own
property&quot; - so if we say that &quot;f&quot; is immutable at &quot;o&quot; then we are implying that &quot;o&quot; has &quot;f&quot;
directly and not on a prototype. More specifically, the immutability inference will prove
that a property on some structure is immutable. This means that, for example, we may have a
structure S1 with property &quot;f&quot; where we claim that &quot;f&quot; at S1 is immutable, but S1 has a
transition to S2 that adds a new property &quot;g&quot; and we may claim that &quot;f&quot; at S2 is actually
mutable. This is mainly for convenience; it allows us to decouple immutability logic from
transition logic. Immutability can be used to constant-fold accesses to objects at
DFG-time. The DFG needs to prove the following to constant-fold the access:
        
- The base of the access must be a constant object pointer. We prove that a property at a
  structure is immutable, but that says nothing of its value; each actual instance of that
  property may have a different value. So, a constant object pointer is needed to get an
  actual constant instance of the immutable value.
        
- A check (or watchpoint) must have been emitted proving that the object has a structure
  that allows loading the property in question.
        
- The replacement watchpoint set of the property in the structure that we've proven the
  object to have is still valid and we add a watchpoint to it lazily. The replacement
  watchpoint set is the key new mechanism that this change adds. It's possible that we have
  proven that the object has one of many structures, in which case each of those structures
  needs a valid replacement watchpoint set.
        
The replacement watchpoint set is created the first time that any access to the property is
cached. A put replace cache will create, and immediately invalidate, the watchpoint set. A
get cache will create the watchpoint set and make it start watching. Any non-cached put
access will invalidate the watchpoint set if one had been created; the underlying algorithm
ensures that checking for the existence of a replacement watchpoint set is very fast in the
common case. This algorithm ensures that no cached access needs to ever do any work to
invalidate, or check the validity of, any replacement watchpoint sets. It also has some
other nice properties:
        
- It's very robust in its definition of immutability. The strictest that it will ever be is
  that for any instance of the object, the property must be written to only once,
  specifically at the time that the property is created. But it's looser than this in
  practice. For example, the property may be written to any number of times before we add
  the final property that the object will have before anyone reads the property; this works
  since for optimization purposes we only care if we detect immutability on the structure
  that the object will have when it is most frequently read from, not any previous
  structure that the object had. Also, we may write to the property any number of times
  before anyone caches accesses to it.
        
- It is mostly orthogonal to structure transitions. No new structures need to be created to
  track the immutability of a property. Hence, there is no risk from this feature causing
  more polymorphism. This is different from the previous &quot;specificValue&quot; constant
  inference, which did cause additional structures to be created and sometimes those
  structures led to fake polymorphism. This feature does leverage existing transitions to
  do some of the watchpointing: property deletions don't fire the replacement watchpoint
  set because that would cause a new structure and so the mandatory structure check would
  fail. Also, this feature is guaranteed to never kick in for uncacheable dictionaries
  because those wouldn't allow for cacheable accesses - and it takes a cacheable access for
  this feature to be enabled.
        
- No memory overhead is incurred except when accesses to the property are cached.
  Dictionary properties will typically have no meta-data for immutability. The number of
  replacement watchpoint sets we allocate is proportional to the number of inline caches in
  the program, which is typically must smaller than the number of structures or even the
  number of objects.
        
This inference is far more powerful than the previous &quot;specificValue&quot; inference, so this
change also removes all of that code. It's interesting that the amount of code that is
changed to remove that feature is almost as big as the amount of code added to support the
new inference - and that's if you include the new tests in the tally. Without new tests,
it appears that the new feature actually touches less code!
        
There is one corner case where the previous &quot;specificValue&quot; inference was more powerful.
You can imagine someone creating objects with functions as self properties on those
objects, such that each object instance had the same function pointers - essentially,
someone might be trying to create a vtable but failing at the whole &quot;one vtable for many
instances&quot; concept. The &quot;specificValue&quot; inference would do very well for such programs,
because a structure check would be sufficient to prove a constant value for all of the
function properties. This new inference will fail because it doesn't track the constant
values of constant properties; instead it detects the immutability of otherwise variable
properties (in the sense that each instance of the property may have a different value).
So, the new inference requires having a particular object instance to actually get the
constant value. I think it's OK to lose this antifeature. It took a lot of code to support
and was a constant source of grief in our transition logic, and there doesn't appear to be
any real evidence that programs benefited from that particular kind of inference since
usually it's the singleton prototype instance that has all of the functions.
        
This change is a speed-up on everything. date-format-xparb and both SunSpider/raytrace and
V8/raytrace seem to be the biggest winners among the macrobenchmarks; they see &gt;5%
speed-ups. Many of our microbenchmarks see very large performance improvements, even 80% in
one case.

* bytecode/ComplexGetStatus.cpp:
(JSC::ComplexGetStatus::computeFor):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt):
(JSC::GetByIdStatus::computeForStubInfo):
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdVariant.cpp:
(JSC::GetByIdVariant::GetByIdVariant):
(JSC::GetByIdVariant::operator=):
(JSC::GetByIdVariant::attemptToMerge):
(JSC::GetByIdVariant::dumpInContext):
* bytecode/GetByIdVariant.h:
(JSC::GetByIdVariant::alternateBase):
(JSC::GetByIdVariant::specificValue): Deleted.
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeForStubInfo):
(JSC::PutByIdStatus::computeFor):
* bytecode/PutByIdVariant.cpp:
(JSC::PutByIdVariant::operator=):
(JSC::PutByIdVariant::setter):
(JSC::PutByIdVariant::dumpInContext):
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::specificValue): Deleted.
* bytecode/Watchpoint.cpp:
(JSC::WatchpointSet::fireAllSlow):
(JSC::WatchpointSet::fireAll): Deleted.
* bytecode/Watchpoint.h:
(JSC::WatchpointSet::fireAll):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::handlePutById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::isStringPrototypeMethodSane):
(JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::tryGetConstantProperty):
(JSC::DFG::Graph::visitChildren):
* dfg/DFGGraph.h:
* dfg/DFGWatchableStructureWatchingPhase.cpp:
(JSC::DFG::WatchableStructureWatchingPhase::run):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
* jit/JITOperations.cpp:
* jit/Repatch.cpp:
(JSC::repatchByIdSelfAccess):
(JSC::generateByIdStub):
(JSC::tryCacheGetByID):
(JSC::tryCachePutByID):
(JSC::tryBuildPutByIdList):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::putToScopeCommon):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::tryCachePutToScopeGlobal):
* runtime/IntendedStructureChain.cpp:
(JSC::IntendedStructureChain::mayInterceptStoreTo):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::putToPrimitive):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
* runtime/JSObject.cpp:
(JSC::JSObject::put):
(JSC::JSObject::putDirectNonIndexAccessor):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::defaultValue):
(JSC::getCallableObjectSlow): Deleted.
(JSC::JSObject::getPropertySpecificValue): Deleted.
* runtime/JSObject.h:
(JSC::JSObject::getDirect):
(JSC::JSObject::getDirectOffset):
(JSC::JSObject::inlineGetOwnPropertySlot):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::putOwnDataProperty):
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectWithoutTransition):
(JSC::getCallableObject): Deleted.
* runtime/JSScope.cpp:
(JSC::abstractAccess):
* runtime/PropertyMapHashTable.h:
(JSC::PropertyMapEntry::PropertyMapEntry):
(JSC::PropertyTable::copy):
* runtime/PropertyTable.cpp:
(JSC::PropertyTable::clone):
(JSC::PropertyTable::PropertyTable):
(JSC::PropertyTable::visitChildren): Deleted.
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::addPropertyTransitionToExistingStructureImpl):
(JSC::Structure::addPropertyTransitionToExistingStructure):
(JSC::Structure::addPropertyTransitionToExistingStructureConcurrently):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::changePrototypeTransition):
(JSC::Structure::attributeChangeTransition):
(JSC::Structure::toDictionaryTransition):
(JSC::Structure::preventExtensionsTransition):
(JSC::Structure::takePropertyTableOrCloneIfPinned):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::addPropertyWithoutTransition):
(JSC::Structure::allocateRareData):
(JSC::Structure::ensurePropertyReplacementWatchpointSet):
(JSC::Structure::startWatchingPropertyForReplacements):
(JSC::Structure::didCachePropertyReplacement):
(JSC::Structure::startWatchingInternalProperties):
(JSC::Structure::copyPropertyTable):
(JSC::Structure::copyPropertyTableForPinning):
(JSC::Structure::getConcurrently):
(JSC::Structure::get):
(JSC::Structure::add):
(JSC::Structure::visitChildren):
(JSC::Structure::prototypeChainMayInterceptStoreTo):
(JSC::Structure::dump):
(JSC::Structure::despecifyDictionaryFunction): Deleted.
(JSC::Structure::despecifyFunctionTransition): Deleted.
(JSC::Structure::despecifyFunction): Deleted.
(JSC::Structure::despecifyAllFunctions): Deleted.
(JSC::Structure::putSpecificValue): Deleted.
* runtime/Structure.h:
(JSC::Structure::startWatchingPropertyForReplacements):
(JSC::Structure::startWatchingInternalPropertiesIfNecessary):
(JSC::Structure::startWatchingInternalPropertiesIfNecessaryForEntireChain):
(JSC::Structure::transitionDidInvolveSpecificValue): Deleted.
(JSC::Structure::disableSpecificFunctionTracking): Deleted.
* runtime/StructureInlines.h:
(JSC::Structure::getConcurrently):
(JSC::Structure::didReplaceProperty):
(JSC::Structure::propertyReplacementWatchpointSet):
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::destroy):
* runtime/StructureRareData.h:
* tests/stress/infer-constant-global-property.js: Added.
(foo.Math.sin):
(foo):
* tests/stress/infer-constant-property.js: Added.
(foo):
* tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js: Added.
(foo):
(bar):
* tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js: Added.
(foo):
(bar):
* tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js: Added.
(foo):
(bar):
* tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js: Added.
(foo):
(bar):
* tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js: Added.
(foo):
(bar):
* tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js: Added.
(foo):
(bar):

LayoutTests: 

* js/regress/infer-constant-global-property-expected.txt: Added.
* js/regress/infer-constant-global-property.html: Added.
* js/regress/infer-constant-property-expected.txt: Added.
* js/regress/infer-constant-property.html: Added.
* js/regress/script-tests/infer-constant-global-property.js: Added.
* js/regress/script-tests/infer-constant-property.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsChangeLog">branches/ftlopt/LayoutTests/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreChangeLog">branches/ftlopt/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeComplexGetStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdVariantcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeWatchpointcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeWatchpointh">branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGFixupPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGGraphcpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGGraphh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGWatchableStructureWatchingPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitJITOperationscpp">branches/ftlopt/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitRepatchcpp">branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorellintLLIntSlowPathscpp">branches/ftlopt/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeCommonSlowPathsh">branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChaincpp">branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeJSCJSValuecpp">branches/ftlopt/Source/JavaScriptCore/runtime/JSCJSValue.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeJSGlobalObjectcpp">branches/ftlopt/Source/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeJSObjectcpp">branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeJSObjecth">branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeJSScopecpp">branches/ftlopt/Source/JavaScriptCore/runtime/JSScope.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimePropertyMapHashTableh">branches/ftlopt/Source/JavaScriptCore/runtime/PropertyMapHashTable.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimePropertyTablecpp">branches/ftlopt/Source/JavaScriptCore/runtime/PropertyTable.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeStructurecpp">branches/ftlopt/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeStructureh">branches/ftlopt/Source/JavaScriptCore/runtime/Structure.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeStructureInlinesh">branches/ftlopt/Source/JavaScriptCore/runtime/StructureInlines.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeStructureRareDatacpp">branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeStructureRareDatah">branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsjsregressinferconstantglobalpropertyexpectedtxt">branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressinferconstantglobalpropertyhtml">branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressinferconstantpropertyexpectedtxt">branches/ftlopt/LayoutTests/js/regress/infer-constant-property-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressinferconstantpropertyhtml">branches/ftlopt/LayoutTests/js/regress/infer-constant-property.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsinferconstantglobalpropertyjs">branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-global-property.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsinferconstantpropertyjs">branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-property.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressinferconstantglobalpropertyjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-global-property.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressinferconstantpropertyjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-property.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressjitcachepolyreplacethencachegetandfoldtheninvalidatejs">branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressjitcachereplacethencachegetandfoldtheninvalidatejs">branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressjitputtoscopeglobalcachewatchpointinvalidatejs">branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressllintcachereplacethencachegetandfoldtheninvalidatejs">branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressllintputtoscopeglobalcachewatchpointinvalidatejs">branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressrepeatputtoscopeglobalwithsamevaluewatchpointinvalidatejs">branches/ftlopt/Source/JavaScriptCore/tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/LayoutTests/ChangeLog (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/ChangeLog        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/LayoutTests/ChangeLog        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-07-04  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] Infer immutable object properties
+        https://bugs.webkit.org/show_bug.cgi?id=134567
+
+        Reviewed by Mark Hahnenberg.
+
+        * js/regress/infer-constant-global-property-expected.txt: Added.
+        * js/regress/infer-constant-global-property.html: Added.
+        * js/regress/infer-constant-property-expected.txt: Added.
+        * js/regress/infer-constant-property.html: Added.
+        * js/regress/script-tests/infer-constant-global-property.js: Added.
+        * js/regress/script-tests/infer-constant-property.js: Added.
+
</ins><span class="cx"> 2014-06-30  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Merge r169121 from trunk.
</span></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressinferconstantglobalpropertyexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property-expected.txt (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property-expected.txt        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/infer-constant-global-property
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressinferconstantglobalpropertyhtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property.html (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/infer-constant-global-property.html        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/infer-constant-global-property.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressinferconstantpropertyexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/infer-constant-property-expected.txt (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/infer-constant-property-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/infer-constant-property-expected.txt        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/infer-constant-property
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressinferconstantpropertyhtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/infer-constant-property.html (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/infer-constant-property.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/infer-constant-property.html        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/infer-constant-property.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsinferconstantglobalpropertyjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-global-property.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-global-property.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-global-property.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+(function() {
+    var result = 0;
+    for (var i = 0; i &lt; 1000000; ++i) {
+        result += Math.sin(Math.PI);
+    }
+    if (Math.abs(result) &gt; 1e-8)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsinferconstantpropertyjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-property.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-property.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/infer-constant-property.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+var o = {f:{f:{f:{f:{f:{f:{f:42}}}}}}};
+(function() {
+    var n = 1000000;
+    var result = 0;
+    for (var i = 0; i &lt; n; ++i)
+        result += o.f.f.f.f.f.f.f;
+    
+    if (result != n * 42)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,3 +1,258 @@
</span><ins>+2014-07-04  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] Infer immutable object properties
+        https://bugs.webkit.org/show_bug.cgi?id=134567
+
+        Reviewed by Mark Hahnenberg.
+        
+        This introduces a new way of inferring immutable object properties. A property is said to
+        be immutable if after its creation (i.e. the transition that creates it), we never
+        overwrite it (i.e. replace it) or delete it. Immutability is a property of an &quot;own
+        property&quot; - so if we say that &quot;f&quot; is immutable at &quot;o&quot; then we are implying that &quot;o&quot; has &quot;f&quot;
+        directly and not on a prototype. More specifically, the immutability inference will prove
+        that a property on some structure is immutable. This means that, for example, we may have a
+        structure S1 with property &quot;f&quot; where we claim that &quot;f&quot; at S1 is immutable, but S1 has a
+        transition to S2 that adds a new property &quot;g&quot; and we may claim that &quot;f&quot; at S2 is actually
+        mutable. This is mainly for convenience; it allows us to decouple immutability logic from
+        transition logic. Immutability can be used to constant-fold accesses to objects at
+        DFG-time. The DFG needs to prove the following to constant-fold the access:
+        
+        - The base of the access must be a constant object pointer. We prove that a property at a
+          structure is immutable, but that says nothing of its value; each actual instance of that
+          property may have a different value. So, a constant object pointer is needed to get an
+          actual constant instance of the immutable value.
+        
+        - A check (or watchpoint) must have been emitted proving that the object has a structure
+          that allows loading the property in question.
+        
+        - The replacement watchpoint set of the property in the structure that we've proven the
+          object to have is still valid and we add a watchpoint to it lazily. The replacement
+          watchpoint set is the key new mechanism that this change adds. It's possible that we have
+          proven that the object has one of many structures, in which case each of those structures
+          needs a valid replacement watchpoint set.
+        
+        The replacement watchpoint set is created the first time that any access to the property is
+        cached. A put replace cache will create, and immediately invalidate, the watchpoint set. A
+        get cache will create the watchpoint set and make it start watching. Any non-cached put
+        access will invalidate the watchpoint set if one had been created; the underlying algorithm
+        ensures that checking for the existence of a replacement watchpoint set is very fast in the
+        common case. This algorithm ensures that no cached access needs to ever do any work to
+        invalidate, or check the validity of, any replacement watchpoint sets. It also has some
+        other nice properties:
+        
+        - It's very robust in its definition of immutability. The strictest that it will ever be is
+          that for any instance of the object, the property must be written to only once,
+          specifically at the time that the property is created. But it's looser than this in
+          practice. For example, the property may be written to any number of times before we add
+          the final property that the object will have before anyone reads the property; this works
+          since for optimization purposes we only care if we detect immutability on the structure
+          that the object will have when it is most frequently read from, not any previous
+          structure that the object had. Also, we may write to the property any number of times
+          before anyone caches accesses to it.
+        
+        - It is mostly orthogonal to structure transitions. No new structures need to be created to
+          track the immutability of a property. Hence, there is no risk from this feature causing
+          more polymorphism. This is different from the previous &quot;specificValue&quot; constant
+          inference, which did cause additional structures to be created and sometimes those
+          structures led to fake polymorphism. This feature does leverage existing transitions to
+          do some of the watchpointing: property deletions don't fire the replacement watchpoint
+          set because that would cause a new structure and so the mandatory structure check would
+          fail. Also, this feature is guaranteed to never kick in for uncacheable dictionaries
+          because those wouldn't allow for cacheable accesses - and it takes a cacheable access for
+          this feature to be enabled.
+        
+        - No memory overhead is incurred except when accesses to the property are cached.
+          Dictionary properties will typically have no meta-data for immutability. The number of
+          replacement watchpoint sets we allocate is proportional to the number of inline caches in
+          the program, which is typically must smaller than the number of structures or even the
+          number of objects.
+        
+        This inference is far more powerful than the previous &quot;specificValue&quot; inference, so this
+        change also removes all of that code. It's interesting that the amount of code that is
+        changed to remove that feature is almost as big as the amount of code added to support the
+        new inference - and that's if you include the new tests in the tally. Without new tests,
+        it appears that the new feature actually touches less code!
+        
+        There is one corner case where the previous &quot;specificValue&quot; inference was more powerful.
+        You can imagine someone creating objects with functions as self properties on those
+        objects, such that each object instance had the same function pointers - essentially,
+        someone might be trying to create a vtable but failing at the whole &quot;one vtable for many
+        instances&quot; concept. The &quot;specificValue&quot; inference would do very well for such programs,
+        because a structure check would be sufficient to prove a constant value for all of the
+        function properties. This new inference will fail because it doesn't track the constant
+        values of constant properties; instead it detects the immutability of otherwise variable
+        properties (in the sense that each instance of the property may have a different value).
+        So, the new inference requires having a particular object instance to actually get the
+        constant value. I think it's OK to lose this antifeature. It took a lot of code to support
+        and was a constant source of grief in our transition logic, and there doesn't appear to be
+        any real evidence that programs benefited from that particular kind of inference since
+        usually it's the singleton prototype instance that has all of the functions.
+        
+        This change is a speed-up on everything. date-format-xparb and both SunSpider/raytrace and
+        V8/raytrace seem to be the biggest winners among the macrobenchmarks; they see &gt;5%
+        speed-ups. Many of our microbenchmarks see very large performance improvements, even 80% in
+        one case.
+
+        * bytecode/ComplexGetStatus.cpp:
+        (JSC::ComplexGetStatus::computeFor):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFromLLInt):
+        (JSC::GetByIdStatus::computeForStubInfo):
+        (JSC::GetByIdStatus::computeFor):
+        * bytecode/GetByIdVariant.cpp:
+        (JSC::GetByIdVariant::GetByIdVariant):
+        (JSC::GetByIdVariant::operator=):
+        (JSC::GetByIdVariant::attemptToMerge):
+        (JSC::GetByIdVariant::dumpInContext):
+        * bytecode/GetByIdVariant.h:
+        (JSC::GetByIdVariant::alternateBase):
+        (JSC::GetByIdVariant::specificValue): Deleted.
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeForStubInfo):
+        (JSC::PutByIdStatus::computeFor):
+        * bytecode/PutByIdVariant.cpp:
+        (JSC::PutByIdVariant::operator=):
+        (JSC::PutByIdVariant::setter):
+        (JSC::PutByIdVariant::dumpInContext):
+        * bytecode/PutByIdVariant.h:
+        (JSC::PutByIdVariant::specificValue): Deleted.
+        * bytecode/Watchpoint.cpp:
+        (JSC::WatchpointSet::fireAllSlow):
+        (JSC::WatchpointSet::fireAll): Deleted.
+        * bytecode/Watchpoint.h:
+        (JSC::WatchpointSet::fireAll):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleGetByOffset):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::handlePutById):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::isStringPrototypeMethodSane):
+        (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::tryGetConstantProperty):
+        (JSC::DFG::Graph::visitChildren):
+        * dfg/DFGGraph.h:
+        * dfg/DFGWatchableStructureWatchingPhase.cpp:
+        (JSC::DFG::WatchableStructureWatchingPhase::run):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
+        * jit/JITOperations.cpp:
+        * jit/Repatch.cpp:
+        (JSC::repatchByIdSelfAccess):
+        (JSC::generateByIdStub):
+        (JSC::tryCacheGetByID):
+        (JSC::tryCachePutByID):
+        (JSC::tryBuildPutByIdList):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        (JSC::LLInt::putToScopeCommon):
+        * runtime/CommonSlowPaths.h:
+        (JSC::CommonSlowPaths::tryCachePutToScopeGlobal):
+        * runtime/IntendedStructureChain.cpp:
+        (JSC::IntendedStructureChain::mayInterceptStoreTo):
+        * runtime/JSCJSValue.cpp:
+        (JSC::JSValue::putToPrimitive):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::put):
+        (JSC::JSObject::putDirectNonIndexAccessor):
+        (JSC::JSObject::deleteProperty):
+        (JSC::JSObject::defaultValue):
+        (JSC::getCallableObjectSlow): Deleted.
+        (JSC::JSObject::getPropertySpecificValue): Deleted.
+        * runtime/JSObject.h:
+        (JSC::JSObject::getDirect):
+        (JSC::JSObject::getDirectOffset):
+        (JSC::JSObject::inlineGetOwnPropertySlot):
+        (JSC::JSObject::putDirectInternal):
+        (JSC::JSObject::putOwnDataProperty):
+        (JSC::JSObject::putDirect):
+        (JSC::JSObject::putDirectWithoutTransition):
+        (JSC::getCallableObject): Deleted.
+        * runtime/JSScope.cpp:
+        (JSC::abstractAccess):
+        * runtime/PropertyMapHashTable.h:
+        (JSC::PropertyMapEntry::PropertyMapEntry):
+        (JSC::PropertyTable::copy):
+        * runtime/PropertyTable.cpp:
+        (JSC::PropertyTable::clone):
+        (JSC::PropertyTable::PropertyTable):
+        (JSC::PropertyTable::visitChildren): Deleted.
+        * runtime/Structure.cpp:
+        (JSC::Structure::Structure):
+        (JSC::Structure::materializePropertyMap):
+        (JSC::Structure::addPropertyTransitionToExistingStructureImpl):
+        (JSC::Structure::addPropertyTransitionToExistingStructure):
+        (JSC::Structure::addPropertyTransitionToExistingStructureConcurrently):
+        (JSC::Structure::addPropertyTransition):
+        (JSC::Structure::changePrototypeTransition):
+        (JSC::Structure::attributeChangeTransition):
+        (JSC::Structure::toDictionaryTransition):
+        (JSC::Structure::preventExtensionsTransition):
+        (JSC::Structure::takePropertyTableOrCloneIfPinned):
+        (JSC::Structure::nonPropertyTransition):
+        (JSC::Structure::addPropertyWithoutTransition):
+        (JSC::Structure::allocateRareData):
+        (JSC::Structure::ensurePropertyReplacementWatchpointSet):
+        (JSC::Structure::startWatchingPropertyForReplacements):
+        (JSC::Structure::didCachePropertyReplacement):
+        (JSC::Structure::startWatchingInternalProperties):
+        (JSC::Structure::copyPropertyTable):
+        (JSC::Structure::copyPropertyTableForPinning):
+        (JSC::Structure::getConcurrently):
+        (JSC::Structure::get):
+        (JSC::Structure::add):
+        (JSC::Structure::visitChildren):
+        (JSC::Structure::prototypeChainMayInterceptStoreTo):
+        (JSC::Structure::dump):
+        (JSC::Structure::despecifyDictionaryFunction): Deleted.
+        (JSC::Structure::despecifyFunctionTransition): Deleted.
+        (JSC::Structure::despecifyFunction): Deleted.
+        (JSC::Structure::despecifyAllFunctions): Deleted.
+        (JSC::Structure::putSpecificValue): Deleted.
+        * runtime/Structure.h:
+        (JSC::Structure::startWatchingPropertyForReplacements):
+        (JSC::Structure::startWatchingInternalPropertiesIfNecessary):
+        (JSC::Structure::startWatchingInternalPropertiesIfNecessaryForEntireChain):
+        (JSC::Structure::transitionDidInvolveSpecificValue): Deleted.
+        (JSC::Structure::disableSpecificFunctionTracking): Deleted.
+        * runtime/StructureInlines.h:
+        (JSC::Structure::getConcurrently):
+        (JSC::Structure::didReplaceProperty):
+        (JSC::Structure::propertyReplacementWatchpointSet):
+        * runtime/StructureRareData.cpp:
+        (JSC::StructureRareData::destroy):
+        * runtime/StructureRareData.h:
+        * tests/stress/infer-constant-global-property.js: Added.
+        (foo.Math.sin):
+        (foo):
+        * tests/stress/infer-constant-property.js: Added.
+        (foo):
+        * tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js: Added.
+        (foo):
+        (bar):
+        * tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js: Added.
+        (foo):
+        (bar):
+        * tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js: Added.
+        (foo):
+        (bar):
+        * tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js: Added.
+        (foo):
+        (bar):
+        * tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js: Added.
+        (foo):
+        (bar):
+        * tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js: Added.
+        (foo):
+        (bar):
+
</ins><span class="cx"> 2014-07-03  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add more coverage for the profile_types_with_high_fidelity op code.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeComplexGetStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -46,8 +46,6 @@
</span><span class="cx">     ComplexGetStatus result;
</span><span class="cx">     result.m_kind = Inlineable;
</span><span class="cx">     
</span><del>-    JSCell* specificValue;
-    
</del><span class="cx">     if (chain) {
</span><span class="cx">         result.m_chain = adoptRef(new IntendedStructureChain(
</span><span class="cx">             profiledBlock, headStructure, chain, chainCount));
</span><span class="lines">@@ -65,18 +63,12 @@
</span><span class="cx">         ASSERT_UNUSED(currentObject, currentObject);
</span><span class="cx">         
</span><span class="cx">         result.m_offset = currentStructure-&gt;getConcurrently(
</span><del>-            *profiledBlock-&gt;vm(), uid, result.m_attributes, specificValue);
-        if (currentStructure-&gt;isDictionary())
-            specificValue = 0;
</del><ins>+            *profiledBlock-&gt;vm(), uid, result.m_attributes);
</ins><span class="cx">     } else {
</span><span class="cx">         result.m_offset = headStructure-&gt;getConcurrently(
</span><del>-            *profiledBlock-&gt;vm(), uid, result.m_attributes, specificValue);
-        if (headStructure-&gt;isDictionary())
-            specificValue = 0;
</del><ins>+            *profiledBlock-&gt;vm(), uid, result.m_attributes);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    result.m_specificValue = specificValue;
-    
</del><span class="cx">     if (!isValidOffset(result.m_offset))
</span><span class="cx">         return takesSlowPath();
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -85,15 +85,12 @@
</span><span class="cx">         return GetByIdStatus(NoInformation, false);
</span><span class="cx"> 
</span><span class="cx">     unsigned attributesIgnored;
</span><del>-    JSCell* specificValue;
</del><span class="cx">     PropertyOffset offset = structure-&gt;getConcurrently(
</span><del>-        *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
-    if (structure-&gt;isDictionary())
-        specificValue = 0;
</del><ins>+        *profiledBlock-&gt;vm(), uid, attributesIgnored);
</ins><span class="cx">     if (!isValidOffset(offset))
</span><span class="cx">         return GetByIdStatus(NoInformation, false);
</span><span class="cx">     
</span><del>-    return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue));
</del><ins>+    return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset));
</ins><span class="cx"> #else
</span><span class="cx">     return GetByIdStatus(NoInformation, false);
</span><span class="cx"> #endif
</span><span class="lines">@@ -156,18 +153,13 @@
</span><span class="cx">         if (structure-&gt;takesSlowPathInDFGForImpureProperty())
</span><span class="cx">             return GetByIdStatus(slowPathState, true);
</span><span class="cx">         unsigned attributesIgnored;
</span><del>-        JSCell* specificValue;
</del><span class="cx">         GetByIdVariant variant;
</span><span class="cx">         variant.m_offset = structure-&gt;getConcurrently(
</span><del>-            *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
</del><ins>+            *profiledBlock-&gt;vm(), uid, attributesIgnored);
</ins><span class="cx">         if (!isValidOffset(variant.m_offset))
</span><span class="cx">             return GetByIdStatus(slowPathState, true);
</span><span class="cx">         
</span><del>-        if (structure-&gt;isDictionary())
-            specificValue = 0;
-        
</del><span class="cx">         variant.m_structureSet.add(structure);
</span><del>-        variant.m_specificValue = JSValue(specificValue);
</del><span class="cx">         bool didAppend = result.appendVariant(variant);
</span><span class="cx">         ASSERT_UNUSED(didAppend, didAppend);
</span><span class="cx">         return result;
</span><span class="lines">@@ -212,8 +204,7 @@
</span><span class="cx">                 }
</span><span class="cx">                 
</span><span class="cx">                 GetByIdVariant variant(
</span><del>-                    StructureSet(structure), complexGetStatus.offset(),
-                    complexGetStatus.specificValue(), complexGetStatus.chain(),
</del><ins>+                    StructureSet(structure), complexGetStatus.offset(), complexGetStatus.chain(),
</ins><span class="cx">                     std::move(callLinkStatus));
</span><span class="cx">                 
</span><span class="cx">                 if (!result.appendVariant(variant))
</span><span class="lines">@@ -297,16 +288,13 @@
</span><span class="cx">             return GetByIdStatus(TakesSlowPath);
</span><span class="cx">         
</span><span class="cx">         unsigned attributes;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes, specificValue);
</del><ins>+        PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes);
</ins><span class="cx">         if (!isValidOffset(offset))
</span><span class="cx">             return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
</span><span class="cx">         if (attributes &amp; Accessor)
</span><span class="cx">             return GetByIdStatus(MakesCalls); // We could be smarter here, like strenght-reducing this to a Call.
</span><del>-        if (structure-&gt;isDictionary())
-            specificValue = 0;
</del><span class="cx">         
</span><del>-        if (!result.appendVariant(GetByIdVariant(structure, offset, specificValue)))
</del><ins>+        if (!result.appendVariant(GetByIdVariant(structure, offset)))
</ins><span class="cx">             return GetByIdStatus(TakesSlowPath);
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -33,17 +33,15 @@
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> GetByIdVariant::GetByIdVariant(
</span><del>-    const StructureSet&amp; structureSet, PropertyOffset offset, JSValue specificValue,
</del><ins>+    const StructureSet&amp; structureSet, PropertyOffset offset,
</ins><span class="cx">     const IntendedStructureChain* chain, std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus)
</span><span class="cx">     : m_structureSet(structureSet)
</span><span class="cx">     , m_alternateBase(nullptr)
</span><del>-    , m_specificValue(specificValue)
</del><span class="cx">     , m_offset(offset)
</span><span class="cx">     , m_callLinkStatus(std::move(callLinkStatus))
</span><span class="cx"> {
</span><span class="cx">     if (!structureSet.size()) {
</span><span class="cx">         ASSERT(offset == invalidOffset);
</span><del>-        ASSERT(!specificValue);
</del><span class="cx">         ASSERT(!chain);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -66,7 +64,6 @@
</span><span class="cx">     m_structureSet = other.m_structureSet;
</span><span class="cx">     m_constantChecks = other.m_constantChecks;
</span><span class="cx">     m_alternateBase = other.m_alternateBase;
</span><del>-    m_specificValue = other.m_specificValue;
</del><span class="cx">     m_offset = other.m_offset;
</span><span class="cx">     if (other.m_callLinkStatus)
</span><span class="cx">         m_callLinkStatus = std::make_unique&lt;CallLinkStatus&gt;(*other.m_callLinkStatus);
</span><span class="lines">@@ -75,6 +72,16 @@
</span><span class="cx">     return *this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+StructureSet GetByIdVariant::baseStructure() const
+{
+    if (!m_alternateBase)
+        return structureSet();
+    
+    Structure* structure = structureFor(m_constantChecks, m_alternateBase);
+    RELEASE_ASSERT(structure);
+    return structure;
+}
+
</ins><span class="cx"> bool GetByIdVariant::attemptToMerge(const GetByIdVariant&amp; other)
</span><span class="cx"> {
</span><span class="cx">     if (m_alternateBase != other.m_alternateBase)
</span><span class="lines">@@ -86,9 +93,6 @@
</span><span class="cx">     if (!areCompatible(m_constantChecks, other.m_constantChecks))
</span><span class="cx">         return false;
</span><span class="cx">     
</span><del>-    if (m_specificValue != other.m_specificValue)
-        m_specificValue = JSValue();
-
</del><span class="cx">     mergeInto(other.m_constantChecks, m_constantChecks);
</span><span class="cx">     m_structureSet.merge(other.m_structureSet);
</span><span class="cx">     
</span><span class="lines">@@ -112,8 +116,6 @@
</span><span class="cx">         &quot;[&quot;, listDumpInContext(m_constantChecks, context), &quot;]&quot;);
</span><span class="cx">     if (m_alternateBase)
</span><span class="cx">         out.print(&quot;, alternateBase = &quot;, inContext(JSValue(m_alternateBase), context));
</span><del>-    if (specificValue())
-        out.print(&quot;, specificValue = &quot;, inContext(specificValue(), context));
</del><span class="cx">     out.print(&quot;, offset = &quot;, offset());
</span><span class="cx">     if (m_callLinkStatus)
</span><span class="cx">         out.print(&quot;, call = &quot;, *m_callLinkStatus);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -42,8 +42,7 @@
</span><span class="cx"> class GetByIdVariant {
</span><span class="cx"> public:
</span><span class="cx">     GetByIdVariant(
</span><del>-        const StructureSet&amp; structureSet = StructureSet(),
-        PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(),
</del><ins>+        const StructureSet&amp; structureSet = StructureSet(), PropertyOffset offset = invalidOffset,
</ins><span class="cx">         const IntendedStructureChain* chain = nullptr,
</span><span class="cx">         std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus = nullptr);
</span><span class="cx">     
</span><span class="lines">@@ -58,7 +57,7 @@
</span><span class="cx">     StructureSet&amp; structureSet() { return m_structureSet; }
</span><span class="cx">     const ConstantStructureCheckVector&amp; constantChecks() const { return m_constantChecks; }
</span><span class="cx">     JSObject* alternateBase() const { return m_alternateBase; }
</span><del>-    JSValue specificValue() const { return m_specificValue; }
</del><ins>+    StructureSet baseStructure() const;
</ins><span class="cx">     PropertyOffset offset() const { return m_offset; }
</span><span class="cx">     CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); }
</span><span class="cx">     
</span><span class="lines">@@ -73,7 +72,6 @@
</span><span class="cx">     StructureSet m_structureSet;
</span><span class="cx">     ConstantStructureCheckVector m_constantChecks;
</span><span class="cx">     JSObject* m_alternateBase;
</span><del>-    JSValue m_specificValue;
</del><span class="cx">     PropertyOffset m_offset;
</span><span class="cx">     std::unique_ptr&lt;CallLinkStatus&gt; m_callLinkStatus;
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -254,8 +254,8 @@
</span><span class="cx">                                 locker, *stub-&gt;m_callLinkInfo, callExitSiteData));
</span><span class="cx">                     
</span><span class="cx">                     variant = PutByIdVariant::setter(
</span><del>-                        structure, complexGetStatus.offset(), complexGetStatus.specificValue(),
-                        complexGetStatus.chain(), std::move(callLinkStatus));
</del><ins>+                        structure, complexGetStatus.offset(), complexGetStatus.chain(),
+                        std::move(callLinkStatus));
</ins><span class="cx">                 } }
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -334,19 +334,24 @@
</span><span class="cx">             return PutByIdStatus(TakesSlowPath);
</span><span class="cx">     
</span><span class="cx">         unsigned attributes;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes, specificValue);
</del><ins>+        PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes);
</ins><span class="cx">         if (isValidOffset(offset)) {
</span><span class="cx">             if (attributes &amp; CustomAccessor)
</span><span class="cx">                 return PutByIdStatus(MakesCalls);
</span><span class="cx"> 
</span><span class="cx">             if (attributes &amp; (Accessor | ReadOnly))
</span><span class="cx">                 return PutByIdStatus(TakesSlowPath);
</span><del>-            if (specificValue) {
-                // We need the PutById slow path to verify that we're storing the right value into
-                // the specialized slot.
</del><ins>+            
+            WatchpointSet* replaceSet = structure-&gt;propertyReplacementWatchpointSet(offset);
+            if (!replaceSet || replaceSet-&gt;isStillValid()) {
+                // When this executes, it'll create, and fire, this replacement watchpoint set.
+                // That means that  this has probably never executed or that something fishy is
+                // going on. Also, we cannot create or fire the watchpoint set from the concurrent
+                // JIT thread, so even if we wanted to do this, we'd need to have a lazy thingy.
+                // So, better leave this alone and take slow path.
</ins><span class="cx">                 return PutByIdStatus(TakesSlowPath);
</span><span class="cx">             }
</span><ins>+            
</ins><span class="cx">             if (!result.appendVariant(PutByIdVariant::replace(structure, offset)))
</span><span class="cx">                 return PutByIdStatus(TakesSlowPath);
</span><span class="cx">             continue;
</span><span class="lines">@@ -384,22 +389,9 @@
</span><span class="cx">         }
</span><span class="cx">     
</span><span class="cx">         // We only optimize if there is already a structure that the transition is cached to.
</span><del>-        // Among other things, this allows us to guard against a transition with a specific
-        // value.
-        //
-        // - If we're storing a value that could be specific: this would only be a problem if
-        //   the existing transition did have a specific value already, since if it didn't,
-        //   then we would behave &quot;as if&quot; we were not storing a specific value. If it did
-        //   have a specific value, then we'll know - the fact that we pass 0 for
-        //   specificValue will tell us.
-        //
-        // - If we're not storing a value that could be specific: again, this would only be a
-        //   problem if the existing transition did have a specific value, which we check for
-        //   by passing 0 for the specificValue.
-        Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset);
</del><ins>+        Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, offset);
</ins><span class="cx">         if (!transition)
</span><del>-            return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above.
-        ASSERT(!transition-&gt;transitionDidInvolveSpecificValue());
</del><ins>+            return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">         ASSERT(isValidOffset(offset));
</span><span class="cx">     
</span><span class="cx">         bool didAppend = result.appendVariant(
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -45,7 +45,6 @@
</span><span class="cx">     m_newStructure = other.m_newStructure;
</span><span class="cx">     m_constantChecks = other.m_constantChecks;
</span><span class="cx">     m_alternateBase = other.m_alternateBase;
</span><del>-    m_specificValue = other.m_specificValue;
</del><span class="cx">     m_offset = other.m_offset;
</span><span class="cx">     if (other.m_callLinkStatus)
</span><span class="cx">         m_callLinkStatus = std::make_unique&lt;CallLinkStatus&gt;(*other.m_callLinkStatus);
</span><span class="lines">@@ -78,7 +77,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PutByIdVariant PutByIdVariant::setter(
</span><del>-    const StructureSet&amp; structure, PropertyOffset offset, JSValue specificValue,
</del><ins>+    const StructureSet&amp; structure, PropertyOffset offset,
</ins><span class="cx">     IntendedStructureChain* chain, std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus)
</span><span class="cx"> {
</span><span class="cx">     PutByIdVariant result;
</span><span class="lines">@@ -89,7 +88,6 @@
</span><span class="cx">         result.m_alternateBase = chain-&gt;terminalPrototype();
</span><span class="cx">     }
</span><span class="cx">     result.m_offset = offset;
</span><del>-    result.m_specificValue = specificValue;
</del><span class="cx">     result.m_callLinkStatus = std::move(callLinkStatus);
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="lines">@@ -134,6 +132,18 @@
</span><span class="cx">     return kind() == Setter;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+StructureSet PutByIdVariant::baseStructure() const
+{
+    ASSERT(kind() == Setter);
+    
+    if (!m_alternateBase)
+        return structure();
+    
+    Structure* structure = structureFor(m_constantChecks, m_alternateBase);
+    RELEASE_ASSERT(structure);
+    return structure;
+}
+
</ins><span class="cx"> bool PutByIdVariant::attemptToMerge(const PutByIdVariant&amp; other)
</span><span class="cx"> {
</span><span class="cx">     if (m_offset != other.m_offset)
</span><span class="lines">@@ -229,8 +239,6 @@
</span><span class="cx">             listDumpInContext(constantChecks(), context), &quot;]&quot;);
</span><span class="cx">         if (m_alternateBase)
</span><span class="cx">             out.print(&quot;, alternateBase = &quot;, inContext(JSValue(m_alternateBase), context));
</span><del>-        if (m_specificValue)
-            out.print(&quot;, specificValue = &quot;, inContext(m_specificValue, context));
</del><span class="cx">         out.print(&quot;, offset = &quot;, m_offset);
</span><span class="cx">         out.print(&quot;, call = &quot;, *m_callLinkStatus);
</span><span class="cx">         out.print(&quot;&gt;&quot;);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">         const IntendedStructureChain* structureChain, PropertyOffset offset);
</span><span class="cx">     
</span><span class="cx">     static PutByIdVariant setter(
</span><del>-        const StructureSet&amp; structure, PropertyOffset offset, JSValue specificValue,
</del><ins>+        const StructureSet&amp; structure, PropertyOffset offset,
</ins><span class="cx">         IntendedStructureChain* chain, std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus);
</span><span class="cx">     
</span><span class="cx">     Kind kind() const { return m_kind; }
</span><span class="lines">@@ -117,11 +117,7 @@
</span><span class="cx">         return m_alternateBase;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    JSValue specificValue() const
-    {
-        ASSERT(kind() == Setter);
-        return m_specificValue;
-    }
</del><ins>+    StructureSet baseStructure() const;
</ins><span class="cx">     
</span><span class="cx">     CallLinkStatus* callLinkStatus() const
</span><span class="cx">     {
</span><span class="lines">@@ -142,7 +138,6 @@
</span><span class="cx">     Structure* m_newStructure;
</span><span class="cx">     ConstantStructureCheckVector m_constantChecks;
</span><span class="cx">     JSObject* m_alternateBase;
</span><del>-    JSValue m_specificValue;
</del><span class="cx">     PropertyOffset m_offset;
</span><span class="cx">     std::unique_ptr&lt;CallLinkStatus&gt; m_callLinkStatus;
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeWatchpointcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -70,11 +70,6 @@
</span><span class="cx">     m_state = IsWatched;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WatchpointSet::fireAll(const char* reason)
-{
-    fireAll(StringFireDetail(reason));
-}
-
</del><span class="cx"> void WatchpointSet::fireAllSlow(const FireDetail&amp; detail)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(state() == IsWatched);
</span><span class="lines">@@ -85,6 +80,11 @@
</span><span class="cx">     WTF::storeStoreFence();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WatchpointSet::fireAllSlow(const char* reason)
+{
+    fireAllSlow(StringFireDetail(reason));
+}
+
</ins><span class="cx"> void WatchpointSet::fireAllWatchpoints(const FireDetail&amp; detail)
</span><span class="cx"> {
</span><span class="cx">     while (!m_set.isEmpty())
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeWatchpointh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/Watchpoint.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -131,12 +131,17 @@
</span><span class="cx">     
</span><span class="cx">     void fireAll(const FireDetail&amp; detail)
</span><span class="cx">     {
</span><del>-        if (state() != IsWatched)
</del><ins>+        if (LIKELY(state() != IsWatched))
</ins><span class="cx">             return;
</span><span class="cx">         fireAllSlow(detail);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    JS_EXPORT_PRIVATE void fireAll(const char* reason);
</del><ins>+    void fireAll(const char* reason)
+    {
+        if (LIKELY(state() != IsWatched))
+            return;
+        fireAllSlow(reason);
+    }
</ins><span class="cx">     
</span><span class="cx">     void touch(const FireDetail&amp; detail)
</span><span class="cx">     {
</span><span class="lines">@@ -157,6 +162,7 @@
</span><span class="cx">     int8_t* addressOfSetIsNotEmpty() { return &amp;m_setIsNotEmpty; }
</span><span class="cx">     
</span><span class="cx">     JS_EXPORT_PRIVATE void fireAllSlow(const FireDetail&amp;); // Call only if you've checked isWatched.
</span><ins>+    JS_EXPORT_PRIVATE void fireAllSlow(const char* reason); // Ditto.
</ins><span class="cx">     
</span><span class="cx"> private:
</span><span class="cx">     void fireAllWatchpoints(const FireDetail&amp;);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;DFGAbstractInterpreter.h&quot;
</span><span class="cx"> #include &quot;GetByIdStatus.h&quot;
</span><ins>+#include &quot;GetterSetter.h&quot;
</ins><span class="cx"> #include &quot;Operations.h&quot;
</span><span class="cx"> #include &quot;PutByIdStatus.h&quot;
</span><span class="cx"> #include &quot;StringObject.h&quot;
</span><span class="lines">@@ -1387,14 +1388,17 @@
</span><span class="cx">                 // something more subtle?
</span><span class="cx">                 AbstractValue result;
</span><span class="cx">                 for (unsigned i = status.numVariants(); i--;) {
</span><del>-                    if (!status[i].specificValue()) {
</del><ins>+                    DFG_ASSERT(m_graph, node, !status[i].alternateBase());
+                    JSValue constantResult =
+                        m_graph.tryGetConstantProperty(value, status[i].offset());
+                    if (!constantResult) {
</ins><span class="cx">                         result.makeHeapTop();
</span><span class="cx">                         break;
</span><span class="cx">                     }
</span><span class="cx">                     
</span><span class="cx">                     AbstractValue thisResult;
</span><span class="cx">                     thisResult.set(
</span><del>-                        m_graph, *m_graph.freeze(status[i].specificValue()),
</del><ins>+                        m_graph, *m_graph.freeze(constantResult),
</ins><span class="cx">                         m_state.structureClobberState());
</span><span class="cx">                     result.merge(thisResult);
</span><span class="cx">                 }
</span><span class="lines">@@ -1569,11 +1573,25 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case GetByOffset: {
</span><ins>+        StorageAccessData data = m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()];
+        JSValue result = m_graph.tryGetConstantProperty(forNode(node-&gt;child2()), data.offset);
+        if (result) {
+            setConstant(node, *m_graph.freeze(result));
+            break;
+        }
+        
</ins><span class="cx">         forNode(node).makeHeapTop();
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case GetGetterSetterByOffset: {
</span><ins>+        StorageAccessData data = m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()];
+        JSValue result = m_graph.tryGetConstantProperty(forNode(node-&gt;child2()), data.offset);
+        if (result &amp;&amp; jsDynamicCast&lt;GetterSetter*&gt;(result)) {
+            setConstant(node, *m_graph.freeze(result));
+            break;
+        }
+        
</ins><span class="cx">         forNode(node).set(m_graph, m_graph.m_vm.getterSetterStructure.get());
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -1602,14 +1620,23 @@
</span><span class="cx">             if (set.isEmpty())
</span><span class="cx">                 continue;
</span><span class="cx">             baseSet.merge(set);
</span><del>-            if (!variant.specificValue()) {
</del><ins>+            
+            JSValue baseForLoad;
+            if (variant.alternateBase())
+                baseForLoad = variant.alternateBase();
+            else
+                baseForLoad = base.m_value;
+            JSValue constantResult =
+                m_graph.tryGetConstantProperty(
+                    baseForLoad, variant.baseStructure(), variant.offset());
+            if (!constantResult) {
</ins><span class="cx">                 result.makeHeapTop();
</span><span class="cx">                 continue;
</span><span class="cx">             }
</span><span class="cx">             AbstractValue thisResult;
</span><span class="cx">             thisResult.set(
</span><span class="cx">                 m_graph,
</span><del>-                *m_graph.freeze(variant.specificValue()),
</del><ins>+                *m_graph.freeze(constantResult),
</ins><span class="cx">                 m_state.structureClobberState());
</span><span class="cx">             result.merge(thisResult);
</span><span class="cx">         }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -187,7 +187,7 @@
</span><span class="cx">     bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType);
</span><span class="cx">     bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
</span><span class="cx">     Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value);
</span><del>-    Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, NodeType op = GetByOffset);
</del><ins>+    Node* handleGetByOffset(SpeculatedType, Node* base, const StructureSet&amp;, unsigned identifierNumber, PropertyOffset, NodeType op = GetByOffset);
</ins><span class="cx">     void handleGetById(
</span><span class="cx">         int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber,
</span><span class="cx">         const GetByIdStatus&amp;);
</span><span class="lines">@@ -1676,8 +1676,15 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset, NodeType op)
</del><ins>+Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, const StructureSet&amp; structureSet, unsigned identifierNumber, PropertyOffset offset, NodeType op)
</ins><span class="cx"> {
</span><ins>+    if (base-&gt;hasConstant()) {
+        if (JSValue constant = m_graph.tryGetConstantProperty(base-&gt;asJSValue(), structureSet, offset)) {
+            addToGraph(Phantom, base);
+            return weakJSConstant(constant);
+        }
+    }
+    
</ins><span class="cx">     Node* propertyStorage;
</span><span class="cx">     if (isInlineOffset(offset))
</span><span class="cx">         propertyStorage = base;
</span><span class="lines">@@ -1772,21 +1779,14 @@
</span><span class="cx">     // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to
</span><span class="cx">     // ensure that the base of the original get_by_id is kept alive until we're done with
</span><span class="cx">     // all of the speculations. We only insert the Phantom if there had been a CheckStructure
</span><del>-    // on something other than the base following the CheckStructure on base, or if the
-    // access was compiled to a WeakJSConstant specific value, in which case we might not
-    // have any explicit use of the base at all.
-    if (variant.specificValue() || originalBase != base)
</del><ins>+    // on something other than the base following the CheckStructure on base.
+    if (originalBase != base)
</ins><span class="cx">         addToGraph(Phantom, originalBase);
</span><span class="cx">     
</span><del>-    Node* loadedValue;
-    if (variant.specificValue())
-        loadedValue = weakJSConstant(variant.specificValue());
-    else {
-        loadedValue = handleGetByOffset(
-            variant.callLinkStatus() ? SpecCellOther : prediction,
-            base, identifierNumber, variant.offset(),
-            variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset);
-    }
</del><ins>+    Node* loadedValue = handleGetByOffset(
+        variant.callLinkStatus() ? SpecCellOther : prediction,
+        base, variant.baseStructure(), identifierNumber, variant.offset(),
+        variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset);
</ins><span class="cx">     
</span><span class="cx">     if (!variant.callLinkStatus()) {
</span><span class="cx">         set(VirtualRegister(destinationOperand), loadedValue);
</span><span class="lines">@@ -1949,14 +1949,9 @@
</span><span class="cx">         if (variant.alternateBase())
</span><span class="cx">             base = weakJSConstant(variant.alternateBase());
</span><span class="cx">         
</span><del>-        Node* loadedValue;
-        if (variant.specificValue())
-            loadedValue = weakJSConstant(variant.specificValue());
-        else {
-            loadedValue = handleGetByOffset(
-                SpecCellOther, base, identifierNumber, variant.offset(),
-                GetGetterSetterByOffset);
-        }
</del><ins>+        Node* loadedValue = handleGetByOffset(
+            SpecCellOther, base, variant.baseStructure(), identifierNumber, variant.offset(),
+            GetGetterSetterByOffset);
</ins><span class="cx">         
</span><span class="cx">         Node* setter = addToGraph(GetSetter, loadedValue);
</span><span class="cx">         
</span><span class="lines">@@ -2958,10 +2953,7 @@
</span><span class="cx">                 }
</span><span class="cx">                 Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().onlyStructure());
</span><span class="cx">                 addToGraph(Phantom, get(VirtualRegister(scope)));
</span><del>-                if (JSValue specificValue = status[0].specificValue())
-                    set(VirtualRegister(dst), weakJSConstant(specificValue.asCell()));
-                else
-                    set(VirtualRegister(dst), handleGetByOffset(prediction, base, identifierNumber, operand));
</del><ins>+                set(VirtualRegister(dst), handleGetByOffset(prediction, base, status[0].structureSet(), identifierNumber, operand));
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             case GlobalVar:
</span><span class="lines">@@ -2969,16 +2961,16 @@
</span><span class="cx">                 addToGraph(Phantom, get(VirtualRegister(scope)));
</span><span class="cx">                 SymbolTableEntry entry = globalObject-&gt;symbolTable()-&gt;get(uid);
</span><span class="cx">                 VariableWatchpointSet* watchpointSet = entry.watchpointSet();
</span><del>-                JSValue specificValue =
</del><ins>+                JSValue inferredValue =
</ins><span class="cx">                     watchpointSet ? watchpointSet-&gt;inferredValue() : JSValue();
</span><del>-                if (!specificValue) {
</del><ins>+                if (!inferredValue) {
</ins><span class="cx">                     SpeculatedType prediction = getPrediction();
</span><span class="cx">                     set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction)));
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                 
</span><span class="cx">                 addToGraph(VariableWatchpoint, OpInfo(watchpointSet));
</span><del>-                set(VirtualRegister(dst), weakJSConstant(specificValue));
</del><ins>+                set(VirtualRegister(dst), weakJSConstant(inferredValue));
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             case ClosureVar:
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -407,8 +407,13 @@
</span><span class="cx"> 
</span><span class="cx">         addBaseCheck(indexInBlock, node, baseValue, variant.structureSet());
</span><span class="cx">         
</span><del>-        if (variant.specificValue()) {
-            m_graph.convertToConstant(node, m_graph.freeze(variant.specificValue()));
</del><ins>+        JSValue baseForLoad;
+        if (variant.alternateBase())
+            baseForLoad = variant.alternateBase();
+        else
+            baseForLoad = baseValue.m_value;
+        if (JSValue value = m_graph.tryGetConstantProperty(baseForLoad, variant.baseStructure(), variant.offset())) {
+            m_graph.convertToConstant(node, m_graph.freeze(value));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1286,22 +1286,24 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, StringImpl* uid)
</del><ins>+    bool isStringPrototypeMethodSane(
+        JSObject* stringPrototype, Structure* stringPrototypeStructure, StringImpl* uid)
</ins><span class="cx">     {
</span><span class="cx">         unsigned attributesUnused;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = stringPrototypeStructure-&gt;getConcurrently(
-            vm(), uid, attributesUnused, specificValue);
</del><ins>+        PropertyOffset offset =
+            stringPrototypeStructure-&gt;getConcurrently(vm(), uid, attributesUnused);
</ins><span class="cx">         if (!isValidOffset(offset))
</span><span class="cx">             return false;
</span><span class="cx">         
</span><del>-        if (!specificValue)
</del><ins>+        JSValue value = m_graph.tryGetConstantProperty(
+            stringPrototype, stringPrototypeStructure, offset);
+        if (!value)
</ins><span class="cx">             return false;
</span><span class="cx">         
</span><del>-        if (!specificValue-&gt;inherits(JSFunction::info()))
</del><ins>+        JSFunction* function = jsDynamicCast&lt;JSFunction*&gt;(value);
+        if (!function)
</ins><span class="cx">             return false;
</span><span class="cx">         
</span><del>-        JSFunction* function = jsCast&lt;JSFunction*&gt;(specificValue);
</del><span class="cx">         if (function-&gt;executable()-&gt;intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
</span><span class="cx">             return false;
</span><span class="cx">         
</span><span class="lines">@@ -1330,9 +1332,9 @@
</span><span class="cx">         // (that would call toString()). We don't want the DFG to have to distinguish
</span><span class="cx">         // between the two, just because that seems like it would get confusing. So we
</span><span class="cx">         // just require both methods to be sane.
</span><del>-        if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames-&gt;valueOf.impl()))
</del><ins>+        if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames-&gt;valueOf.impl()))
</ins><span class="cx">             return false;
</span><del>-        if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames-&gt;toString.impl()))
</del><ins>+        if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames-&gt;toString.impl()))
</ins><span class="cx">             return false;
</span><span class="cx">         
</span><span class="cx">         return true;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -789,6 +789,71 @@
</span><span class="cx">     return std::max(frameRegisterCount(), requiredRegisterCountForExit());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSValue Graph::tryGetConstantProperty(
+    JSValue base, const StructureSet&amp; structureSet, PropertyOffset offset)
+{
+    if (!base || !base.isObject())
+        return JSValue();
+    
+    JSObject* object = asObject(base);
+    
+    for (unsigned i = structureSet.size(); i--;) {
+        Structure* structure = structureSet[i];
+        WatchpointSet* set = structure-&gt;propertyReplacementWatchpointSet(offset);
+        if (!set || !set-&gt;isStillValid())
+            return JSValue();
+        
+        ASSERT(structure-&gt;isValidOffset(offset));
+        ASSERT(!structure-&gt;isUncacheableDictionary());
+        
+        watchpoints().addLazily(set);
+    }
+    
+    // What follows may require some extra thought. We need this load to load a valid JSValue. If
+    // our profiling makes sense and we're still on track to generate code that won't be
+    // invalidated, then we have nothing to worry about. We do, however, have to worry about
+    // loading - and then using - an invalid JSValue in the case that unbeknownst to us our code
+    // is doomed.
+    //
+    // One argument in favor of this code is that it should definitely work because the butterfly
+    // is always set before the structure. However, we don't currently have a fence between those
+    // stores. It's not clear if this matters, however. We don't ever shrink the property storage.
+    // So, for this to fail, you'd need an access on a constant object pointer such that the inline
+    // caches told us that the object had a structure that it did not *yet* have, and then later,
+    // the object transitioned to that structure that the inline caches had alraedy seen. And then
+    // the processor reordered the stores. Seems unlikely and difficult to test. I believe that
+    // this is worth revisiting but it isn't worth losing sleep over. Filed:
+    // https://bugs.webkit.org/show_bug.cgi?id=134641
+    //
+    // For now, we just do the minimal thing: defend against the structure right now being
+    // incompatible with the getDirect we're trying to do. The easiest way to do that is to
+    // determine if the structure belongs to the proven set.
+    
+    if (!structureSet.contains(object-&gt;structure()))
+        return JSValue();
+    
+    return object-&gt;getDirect(offset);
+}
+
+JSValue Graph::tryGetConstantProperty(JSValue base, Structure* structure, PropertyOffset offset)
+{
+    return tryGetConstantProperty(base, StructureSet(structure), offset);
+}
+
+JSValue Graph::tryGetConstantProperty(
+    JSValue base, const StructureAbstractValue&amp; structure, PropertyOffset offset)
+{
+    if (structure.isTop() || structure.isClobbered())
+        return JSValue();
+    
+    return tryGetConstantProperty(base, structure.set(), offset);
+}
+
+JSValue Graph::tryGetConstantProperty(const AbstractValue&amp; base, PropertyOffset offset)
+{
+    return tryGetConstantProperty(base.m_value, base.m_structure, offset);
+}
+
</ins><span class="cx"> JSActivation* Graph::tryGetActivation(Node* node)
</span><span class="cx"> {
</span><span class="cx">     return node-&gt;dynamicCastConstant&lt;JSActivation*&gt;();
</span><span class="lines">@@ -900,7 +965,6 @@
</span><span class="cx">             case MultiGetByOffset:
</span><span class="cx">                 for (unsigned i = node-&gt;multiGetByOffsetData().variants.size(); i--;) {
</span><span class="cx">                     GetByIdVariant&amp; variant = node-&gt;multiGetByOffsetData().variants[i];
</span><del>-                    visitor.appendUnbarrieredReadOnlyValue(variant.specificValue());
</del><span class="cx">                     const StructureSet&amp; set = variant.structureSet();
</span><span class="cx">                     for (unsigned j = set.size(); j--;)
</span><span class="cx">                         visitor.appendUnbarrieredReadOnlyPointer(set[j]);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -679,6 +679,11 @@
</span><span class="cx">     unsigned requiredRegisterCountForExit();
</span><span class="cx">     unsigned requiredRegisterCountForExecutionAndExit();
</span><span class="cx">     
</span><ins>+    JSValue tryGetConstantProperty(JSValue base, const StructureSet&amp;, PropertyOffset);
+    JSValue tryGetConstantProperty(JSValue base, Structure*, PropertyOffset);
+    JSValue tryGetConstantProperty(JSValue base, const StructureAbstractValue&amp;, PropertyOffset);
+    JSValue tryGetConstantProperty(const AbstractValue&amp;, PropertyOffset);
+    
</ins><span class="cx">     JSActivation* tryGetActivation(Node*);
</span><span class="cx">     WriteBarrierBase&lt;Unknown&gt;* tryGetRegisters(Node*);
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGWatchableStructureWatchingPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -86,7 +86,6 @@
</span><span class="cx">                 case MultiGetByOffset:
</span><span class="cx">                     for (unsigned i = node-&gt;multiGetByOffsetData().variants.size(); i--;) {
</span><span class="cx">                         GetByIdVariant&amp; variant = node-&gt;multiGetByOffsetData().variants[i];
</span><del>-                        tryWatch(m_graph.freeze(variant.specificValue())-&gt;structure());
</del><span class="cx">                         tryWatch(variant.structureSet());
</span><span class="cx">                         // Don't need to watch anything in the structure chain because that would
</span><span class="cx">                         // have been decomposed into CheckStructure's. Don't need to watch the
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -3237,8 +3237,13 @@
</span><span class="cx">             
</span><span class="cx">             GetByIdVariant variant = data.variants[i];
</span><span class="cx">             LValue result;
</span><del>-            if (variant.specificValue())
-                result = m_out.constInt64(JSValue::encode(variant.specificValue()));
</del><ins>+            JSValue constantResult;
+            if (variant.alternateBase()) {
+                constantResult = m_graph.tryGetConstantProperty(
+                    variant.alternateBase(), variant.baseStructure(), variant.offset());
+            }
+            if (constantResult)
+                result = m_out.constInt64(JSValue::encode(constantResult));
</ins><span class="cx">             else {
</span><span class="cx">                 LValue propertyBase;
</span><span class="cx">                 if (variant.alternateBase())
</span><span class="lines">@@ -5103,7 +5108,7 @@
</span><span class="cx">     
</span><span class="cx">     LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</span><span class="cx">     {
</span><del>-        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind()));
</del><ins>+        DFG_ASSERT(m_graph, m_node, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind()));
</ins><span class="cx">         
</span><span class="cx">         if (edge-&gt;op() == JSConstant) {
</span><span class="cx">             JSValue value = edge-&gt;asJSValue();
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/JITOperations.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/JITOperations.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/jit/JITOperations.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1698,9 +1698,13 @@
</span><span class="cx">     // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
</span><span class="cx">     if (slot.isCacheableValue() &amp;&amp; slot.slotBase() == scope &amp;&amp; scope-&gt;structure(vm)-&gt;propertyAccessesAreCacheable()) {
</span><span class="cx">         if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
</span><del>-            ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
-            pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), scope-&gt;structure(vm));
-            pc[6].u.operand = slot.cachedOffset();
</del><ins>+            Structure* structure = scope-&gt;structure(vm);
+            {
+                ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
+                pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), structure);
+                pc[6].u.operand = slot.cachedOffset();
+            }
+            structure-&gt;startWatchingPropertyForReplacements(vm, slot.cachedOffset());
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1730,14 +1734,7 @@
</span><span class="cx">     if (exec-&gt;vm().exception())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
-    if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
-        if (slot.isCacheablePut() &amp;&amp; slot.base() == scope &amp;&amp; scope-&gt;structure()-&gt;propertyAccessesAreCacheable()) {
-            ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
-            pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), scope-&gt;structure());
-            pc[6].u.operand = slot.cachedOffset();
-        }
-    }
</del><ins>+    CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExceptionValue)
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -96,12 +96,14 @@
</span><span class="cx">     repatchCall(repatchBuffer, call, newCalleeFunction);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void repatchByIdSelfAccess(VM&amp; vm, CodeBlock* codeBlock, StructureStubInfo&amp; stubInfo, Structure* structure, const Identifier&amp; propertyName, PropertyOffset offset,
-    const FunctionPtr &amp;slowPathFunction, bool compact)
</del><ins>+static void repatchByIdSelfAccess(
+    VM&amp; vm, CodeBlock* codeBlock, StructureStubInfo&amp; stubInfo, Structure* structure,
+    const Identifier&amp; propertyName, PropertyOffset offset, const FunctionPtr &amp;slowPathFunction,
+    bool compact)
</ins><span class="cx"> {
</span><span class="cx">     if (structure-&gt;typeInfo().newImpurePropertyFiresWatchpoints())
</span><span class="cx">         vm.registerWatchpointForImpureProperty(propertyName, stubInfo.addWatchpoint(codeBlock));
</span><del>-
</del><ins>+    
</ins><span class="cx">     RepatchBuffer repatchBuffer(codeBlock);
</span><span class="cx"> 
</span><span class="cx">     // Only optimize once!
</span><span class="lines">@@ -343,8 +345,11 @@
</span><span class="cx">                 failureCases, scratchGPR);
</span><span class="cx">             currStructure = it-&gt;get();
</span><span class="cx">         }
</span><ins>+        ASSERT(protoObject-&gt;structure() == currStructure);
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    currStructure-&gt;startWatchingPropertyForReplacements(*vm, offset);
+    
</ins><span class="cx">     GPRReg baseForAccessGPR;
</span><span class="cx">     if (chain) {
</span><span class="cx">         stubJit.move(MacroAssembler::TrustedImmPtr(protoObject), scratchGPR);
</span><span class="lines">@@ -693,9 +698,10 @@
</span><span class="cx">     if (slot.slotBase() == baseValue
</span><span class="cx">         &amp;&amp; slot.isCacheableValue()
</span><span class="cx">         &amp;&amp; MacroAssembler::isCompactPtrAlignedAddressOffset(maxOffsetRelativeToPatchedStorage(slot.cachedOffset()))) {
</span><del>-            repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, propertyName, slot.cachedOffset(), operationGetByIdBuildList, true);
-            stubInfo.initGetByIdSelf(*vm, codeBlock-&gt;ownerExecutable(), structure);
-            return true;
</del><ins>+        structure-&gt;startWatchingPropertyForReplacements(*vm, slot.cachedOffset());
+        repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, propertyName, slot.cachedOffset(), operationGetByIdBuildList, true);
+        stubInfo.initGetByIdSelf(*vm, codeBlock-&gt;ownerExecutable(), structure);
+        return true;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     repatchCall(codeBlock, stubInfo.callReturnLocation, operationGetByIdBuildList);
</span><span class="lines">@@ -1178,6 +1184,7 @@
</span><span class="cx">         if (!MacroAssembler::isPtrAlignedAddressOffset(offsetRelativeToPatchedStorage(slot.cachedOffset())))
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><ins>+        structure-&gt;didCachePropertyReplacement(*vm, slot.cachedOffset());
</ins><span class="cx">         repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, ident, slot.cachedOffset(), appropriateListBuildingPutByIdFunction(slot, putKind), false);
</span><span class="cx">         stubInfo.initPutByIdReplace(*vm, codeBlock-&gt;ownerExecutable(), structure);
</span><span class="cx">         return true;
</span><span class="lines">@@ -1295,6 +1302,8 @@
</span><span class="cx">             if (list-&gt;isFull())
</span><span class="cx">                 return false; // Will get here due to recursion.
</span><span class="cx">             
</span><ins>+            structure-&gt;didCachePropertyReplacement(*vm, slot.cachedOffset());
+            
</ins><span class="cx">             // We're now committed to creating the stub. Mogrify the meta-data accordingly.
</span><span class="cx">             emitPutReplaceStub(
</span><span class="cx">                 exec, baseValue, propertyName, slot, stubInfo, putKind,
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorellintLLIntSlowPathscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -693,6 +693,7 @@
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx">             } else {
</span><ins>+                structure-&gt;didCachePropertyReplacement(vm, slot.cachedOffset());
</ins><span class="cx">                 pc[4].u.structure.set(
</span><span class="cx">                     vm, codeBlock-&gt;ownerExecutable(), structure);
</span><span class="cx">                 if (isInlineOffset(slot.cachedOffset())) {
</span><span class="lines">@@ -1425,9 +1426,13 @@
</span><span class="cx">     if (slot.isCacheableValue() &amp;&amp; slot.slotBase() == scope &amp;&amp; scope-&gt;structure()-&gt;propertyAccessesAreCacheable()) {
</span><span class="cx">         if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
</span><span class="cx">             CodeBlock* codeBlock = exec-&gt;codeBlock();
</span><del>-            ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
-            pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), scope-&gt;structure());
-            pc[6].u.operand = slot.cachedOffset();
</del><ins>+            Structure* structure = scope-&gt;structure(vm);
+            {
+                ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
+                pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), structure);
+                pc[6].u.operand = slot.cachedOffset();
+            }
+            structure-&gt;startWatchingPropertyForReplacements(vm, slot.cachedOffset());
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1463,16 +1468,9 @@
</span><span class="cx"> 
</span><span class="cx">     PutPropertySlot slot(scope, codeBlock-&gt;isStrictMode());
</span><span class="cx">     scope-&gt;methodTable()-&gt;put(scope, exec, ident, value, slot);
</span><ins>+    
+    CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot);
</ins><span class="cx"> 
</span><del>-    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
-    if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
-        if (slot.isCacheablePut() &amp;&amp; slot.base() == scope &amp;&amp; scope-&gt;structure()-&gt;propertyAccessesAreCacheable()) {
-            ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
-            pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), scope-&gt;structure());
-            pc[6].u.operand = slot.cachedOffset();
-        }
-    }
-
</del><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeCommonSlowPathsh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -93,6 +93,33 @@
</span><span class="cx">     return baseObj-&gt;hasProperty(exec, property);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void tryCachePutToScopeGlobal(
+    ExecState* exec, CodeBlock* codeBlock, Instruction* pc, JSObject* scope,
+    ResolveModeAndType modeAndType, PutPropertySlot&amp; slot)
+{
+    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
+    
+    if (modeAndType.type() != GlobalProperty &amp;&amp; modeAndType.type() != GlobalPropertyWithVarInjectionChecks)
+        return;
+    
+    if (!slot.isCacheablePut()
+        || slot.base() != scope
+        || !scope-&gt;structure()-&gt;propertyAccessesAreCacheable())
+        return;
+    
+    if (slot.type() == PutPropertySlot::NewProperty) {
+        // Don't cache if we've done a transition. We want to detect the first replace so that we
+        // can invalidate the watchpoint.
+        return;
+    }
+    
+    scope-&gt;structure()-&gt;didCachePropertyReplacement(exec-&gt;vm(), slot.cachedOffset());
+
+    ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
+    pc[5].u.structure.set(exec-&gt;vm(), codeBlock-&gt;ownerExecutable(), scope-&gt;structure());
+    pc[6].u.operand = slot.cachedOffset();
+}
+
</ins><span class="cx"> } // namespace CommonSlowPaths
</span><span class="cx"> 
</span><span class="cx"> class ExecState;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChaincpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -107,8 +107,7 @@
</span><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; i &lt; m_vector.size(); ++i) {
</span><span class="cx">         unsigned attributes;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = m_vector[i]-&gt;getConcurrently(vm, uid, attributes, specificValue);
</del><ins>+        PropertyOffset offset = m_vector[i]-&gt;getConcurrently(vm, uid, attributes);
</ins><span class="cx">         if (!isValidOffset(offset))
</span><span class="cx">             continue;
</span><span class="cx">         if (attributes &amp; (ReadOnly | Accessor))
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeJSCJSValuecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/JSCJSValue.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/JSCJSValue.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/JSCJSValue.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -139,8 +139,7 @@
</span><span class="cx"> 
</span><span class="cx">     for (; ; obj = asObject(prototype)) {
</span><span class="cx">         unsigned attributes;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = obj-&gt;structure()-&gt;get(vm, propertyName, attributes, specificValue);
</del><ins>+        PropertyOffset offset = obj-&gt;structure()-&gt;get(vm, propertyName, attributes);
</ins><span class="cx">         if (offset != invalidOffset) {
</span><span class="cx">             if (attributes &amp; ReadOnly) {
</span><span class="cx">                 if (slot.isStrictMode())
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -282,7 +282,7 @@
</span><span class="cx">     m_functionPrototype.set(vm, this, FunctionPrototype::create(vm, FunctionPrototype::createStructure(vm, this, jsNull()))); // The real prototype will be set once ObjectPrototype is created.
</span><span class="cx">     m_functionStructure.set(vm, this, JSFunction::createStructure(vm, this, m_functionPrototype.get()));
</span><span class="cx">     m_boundFunctionStructure.set(vm, this, JSBoundFunction::createStructure(vm, this, m_functionPrototype.get()));
</span><del>-    m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames-&gt;name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset));
</del><ins>+    m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames-&gt;name, DontDelete | ReadOnly | DontEnum, m_functionNameOffset));
</ins><span class="cx">     m_internalFunctionStructure.set(vm, this, InternalFunction::createStructure(vm, this, m_functionPrototype.get()));
</span><span class="cx">     JSFunction* callFunction = 0;
</span><span class="cx">     JSFunction* applyFunction = 0;
</span><span class="lines">@@ -429,8 +429,8 @@
</span><span class="cx">     PrototypeMap&amp; prototypeMap = vm.prototypeMap;
</span><span class="cx">     Structure* iteratorResultStructure = prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get(), JSFinalObject::defaultInlineCapacity());
</span><span class="cx">     PropertyOffset offset;
</span><del>-    iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames-&gt;done, 0, 0, offset);
-    iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames-&gt;value, 0, 0, offset);
</del><ins>+    iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames-&gt;done, 0, offset);
+    iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames-&gt;value, 0, offset);
</ins><span class="cx">     m_iteratorResultStructure.set(vm, this, iteratorResultStructure);
</span><span class="cx"> 
</span><span class="cx">     m_evalFunction.set(vm, this, JSFunction::create(vm, this, 1, vm.propertyNames-&gt;eval.string(), globalFuncEval));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
</span><span class="cx">  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
</span><del>- *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *  Copyright (C) 2007 Eric Seidel (eric@webkit.org)
</span><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="lines">@@ -55,15 +55,6 @@
</span><span class="cx"> // ArrayConventions.h.
</span><span class="cx"> static unsigned lastArraySize = 0;
</span><span class="cx"> 
</span><del>-JSCell* getCallableObjectSlow(JSCell* cell)
-{
-    if (cell-&gt;type() == JSFunctionType)
-        return cell;
-    if (cell-&gt;structure()-&gt;classInfo()-&gt;isSubClassOf(InternalFunction::info()))
-        return cell;
-    return 0;
-}
-
</del><span class="cx"> STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSObject);
</span><span class="cx"> STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSFinalObject);
</span><span class="cx"> 
</span><span class="lines">@@ -360,7 +351,7 @@
</span><span class="cx">             prototype = obj-&gt;prototype();
</span><span class="cx">             if (prototype.isNull()) {
</span><span class="cx">                 ASSERT(!thisObject-&gt;structure(vm)-&gt;prototypeChainMayInterceptStoreTo(exec-&gt;vm(), propertyName));
</span><del>-                if (!thisObject-&gt;putDirectInternal&lt;PutModePut&gt;(vm, propertyName, value, 0, slot, getCallableObject(value))
</del><ins>+                if (!thisObject-&gt;putDirectInternal&lt;PutModePut&gt;(vm, propertyName, value, 0, slot)
</ins><span class="cx">                     &amp;&amp; slot.isStrictMode())
</span><span class="cx">                     throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
</span><span class="cx">                 return;
</span><span class="lines">@@ -371,8 +362,7 @@
</span><span class="cx">     JSObject* obj;
</span><span class="cx">     for (obj = thisObject; ; obj = asObject(prototype)) {
</span><span class="cx">         unsigned attributes;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = obj-&gt;structure(vm)-&gt;get(vm, propertyName, attributes, specificValue);
</del><ins>+        PropertyOffset offset = obj-&gt;structure(vm)-&gt;get(vm, propertyName, attributes);
</ins><span class="cx">         if (isValidOffset(offset)) {
</span><span class="cx">             if (attributes &amp; ReadOnly) {
</span><span class="cx">                 ASSERT(thisObject-&gt;structure(vm)-&gt;prototypeChainMayInterceptStoreTo(exec-&gt;vm(), propertyName) || obj == thisObject);
</span><span class="lines">@@ -407,7 +397,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ASSERT(!thisObject-&gt;structure(vm)-&gt;prototypeChainMayInterceptStoreTo(exec-&gt;vm(), propertyName) || obj == thisObject);
</span><del>-    if (!thisObject-&gt;putDirectInternal&lt;PutModePut&gt;(vm, propertyName, value, 0, slot, getCallableObject(value)) &amp;&amp; slot.isStrictMode())
</del><ins>+    if (!thisObject-&gt;putDirectInternal&lt;PutModePut&gt;(vm, propertyName, value, 0, slot) &amp;&amp; slot.isStrictMode())
</ins><span class="cx">         throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
</span><span class="cx">     return;
</span><span class="cx"> }
</span><span class="lines">@@ -1227,7 +1217,7 @@
</span><span class="cx"> void JSObject::putDirectNonIndexAccessor(VM&amp; vm, PropertyName propertyName, JSValue value, unsigned attributes)
</span><span class="cx"> {
</span><span class="cx">     PutPropertySlot slot(this);
</span><del>-    putDirectInternal&lt;PutModeDefineOwnProperty&gt;(vm, propertyName, value, attributes, slot, getCallableObject(value));
</del><ins>+    putDirectInternal&lt;PutModeDefineOwnProperty&gt;(vm, propertyName, value, attributes, slot);
</ins><span class="cx"> 
</span><span class="cx">     // putDirect will change our Structure if we add a new property. For
</span><span class="cx">     // getters and setters, though, we also need to change our Structure
</span><span class="lines">@@ -1267,9 +1257,8 @@
</span><span class="cx">         thisObject-&gt;reifyStaticFunctionsForDelete(exec);
</span><span class="cx"> 
</span><span class="cx">     unsigned attributes;
</span><del>-    JSCell* specificValue;
</del><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><del>-    if (isValidOffset(thisObject-&gt;structure(vm)-&gt;get(vm, propertyName, attributes, specificValue))) {
</del><ins>+    if (isValidOffset(thisObject-&gt;structure(vm)-&gt;get(vm, propertyName, attributes))) {
</ins><span class="cx">         if (attributes &amp; DontDelete &amp;&amp; !vm.isInDefineOwnProperty())
</span><span class="cx">             return false;
</span><span class="cx">         thisObject-&gt;removeDirect(vm, propertyName);
</span><span class="lines">@@ -1383,6 +1372,10 @@
</span><span class="cx"> // ECMA 8.6.2.6
</span><span class="cx"> JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
</span><span class="cx"> {
</span><ins>+    // Make sure that whatever default value methods there are on object's prototype chain are
+    // being watched.
+    object-&gt;structure()-&gt;startWatchingInternalPropertiesIfNecessaryForEntireChain(exec-&gt;vm());
+    
</ins><span class="cx">     // Must call toString first for Date objects.
</span><span class="cx">     if ((hint == PreferString) || (hint != PreferNumber &amp;&amp; object-&gt;prototype() == exec-&gt;lexicalGlobalObject()-&gt;datePrototype())) {
</span><span class="cx">         JSValue value = callDefaultValueFunction(exec, object, exec-&gt;propertyNames().toString);
</span><span class="lines">@@ -1446,20 +1439,6 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*&amp; specificValue) const
-{
-    VM&amp; vm = exec-&gt;vm();
-    unsigned attributes;
-    if (isValidOffset(structure(vm)-&gt;get(vm, propertyName, attributes, specificValue)))
-        return true;
-
-    // This could be a function within the static table? - should probably
-    // also look in the hash?  This currently should not be a problem, since
-    // we've currently always call 'get' first, which should have populated
-    // the normal storage.
-    return false;
-}
-
</del><span class="cx"> void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray&amp; propertyNames, EnumerationMode mode)
</span><span class="cx"> {
</span><span class="cx">     propertyNames.setBaseObject(object);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
</span><span class="cx">  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
</span><del>- *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -56,15 +56,6 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*);
-
-inline JSCell* getCallableObject(JSValue value)
-{
-    if (!value.isCell())
-        return 0;
-    return getCallableObjectSlow(value.asCell());
-}
-
</del><span class="cx"> class GetterSetter;
</span><span class="cx"> class InternalFunction;
</span><span class="cx"> class JSFunction;
</span><span class="lines">@@ -491,8 +482,6 @@
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode);
</span><span class="cx"> 
</span><del>-    bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*&amp; specificFunction) const;
-
</del><span class="cx">     // This get function only looks at the property map.
</span><span class="cx">     JSValue getDirect(VM&amp; vm, PropertyName propertyName) const
</span><span class="cx">     {
</span><span class="lines">@@ -501,12 +490,11 @@
</span><span class="cx">         checkOffset(offset, structure-&gt;inlineCapacity());
</span><span class="cx">         return offset != invalidOffset ? getDirect(offset) : JSValue();
</span><span class="cx">     }
</span><del>-
</del><ins>+    
</ins><span class="cx">     JSValue getDirect(VM&amp; vm, PropertyName propertyName, unsigned&amp; attributes) const
</span><span class="cx">     {
</span><del>-        JSCell* specific;
</del><span class="cx">         Structure* structure = this-&gt;structure(vm);
</span><del>-        PropertyOffset offset = structure-&gt;get(vm, propertyName, attributes, specific);
</del><ins>+        PropertyOffset offset = structure-&gt;get(vm, propertyName, attributes);
</ins><span class="cx">         checkOffset(offset, structure-&gt;inlineCapacity());
</span><span class="cx">         return offset != invalidOffset ? getDirect(offset) : JSValue();
</span><span class="cx">     }
</span><span class="lines">@@ -521,9 +509,8 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset getDirectOffset(VM&amp; vm, PropertyName propertyName, unsigned&amp; attributes)
</span><span class="cx">     {
</span><del>-        JSCell* specific;
</del><span class="cx">         Structure* structure = this-&gt;structure(vm);
</span><del>-        PropertyOffset offset = structure-&gt;get(vm, propertyName, attributes, specific);
</del><ins>+        PropertyOffset offset = structure-&gt;get(vm, propertyName, attributes);
</ins><span class="cx">         checkOffset(offset, structure-&gt;inlineCapacity());
</span><span class="cx">         return offset;
</span><span class="cx">     }
</span><span class="lines">@@ -949,7 +936,7 @@
</span><span class="cx">     ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&amp;, ArrayStorage*);
</span><span class="cx">         
</span><span class="cx">     template&lt;PutMode&gt;
</span><del>-    bool putDirectInternal(VM&amp;, PropertyName, JSValue, unsigned attr, PutPropertySlot&amp;, JSCell*);
</del><ins>+    bool putDirectInternal(VM&amp;, PropertyName, JSValue, unsigned attr, PutPropertySlot&amp;);
</ins><span class="cx"> 
</span><span class="cx">     bool inlineGetOwnPropertySlot(ExecState*, VM&amp;, Structure&amp;, PropertyName, PropertySlot&amp;);
</span><span class="cx">     JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&amp;, JSValue, unsigned, PropertyOffset);
</span><span class="lines">@@ -1213,8 +1200,7 @@
</span><span class="cx"> ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, VM&amp; vm, Structure&amp; structure, PropertyName propertyName, PropertySlot&amp; slot)
</span><span class="cx"> {
</span><span class="cx">     unsigned attributes;
</span><del>-    JSCell* specific;
-    PropertyOffset offset = structure.get(vm, propertyName, attributes, specific);
</del><ins>+    PropertyOffset offset = structure.get(vm, propertyName, attributes);
</ins><span class="cx">     if (LIKELY(isValidOffset(offset))) {
</span><span class="cx">         JSValue value = getDirect(offset);
</span><span class="cx">         if (structure.hasGetterSetterProperties() &amp;&amp; value.isGetterSetter())
</span><span class="lines">@@ -1295,7 +1281,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;JSObject::PutMode mode&gt;
</span><del>-inline bool JSObject::putDirectInternal(VM&amp; vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot&amp; slot, JSCell* specificFunction)
</del><ins>+inline bool JSObject::putDirectInternal(VM&amp; vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot&amp; slot)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(value);
</span><span class="cx">     ASSERT(value.isGetterSetter() == !!(attributes &amp; Accessor));
</span><span class="lines">@@ -1305,25 +1291,15 @@
</span><span class="cx">     Structure* structure = this-&gt;structure(vm);
</span><span class="cx">     if (structure-&gt;isDictionary()) {
</span><span class="cx">         unsigned currentAttributes;
</span><del>-        JSCell* currentSpecificFunction;
-        PropertyOffset offset = structure-&gt;get(vm, propertyName, currentAttributes, currentSpecificFunction);
</del><ins>+        PropertyOffset offset = structure-&gt;get(vm, propertyName, currentAttributes);
</ins><span class="cx">         if (offset != invalidOffset) {
</span><del>-            // If there is currently a specific function, and there now either isn't,
-            // or the new value is different, then despecify.
-            if (currentSpecificFunction &amp;&amp; (specificFunction != currentSpecificFunction))
-                structure-&gt;despecifyDictionaryFunction(vm, propertyName);
</del><span class="cx">             if ((mode == PutModePut) &amp;&amp; currentAttributes &amp; ReadOnly)
</span><span class="cx">                 return false;
</span><span class="cx"> 
</span><span class="cx">             putDirect(vm, offset, value);
</span><del>-            // At this point, the objects structure only has a specific value set if previously there
-            // had been one set, and if the new value being specified is the same (otherwise we would
-            // have despecified, above).  So, if currentSpecificFunction is not set, or if the new
-            // value is different (or there is no new value), then the slot now has no value - and
-            // as such it is cachable.
-            // If there was previously a value, and the new value is the same, then we cannot cache.
-            if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
-                slot.setExistingProperty(this, offset);
</del><ins>+            structure-&gt;didReplaceProperty(offset);
+            
+            slot.setExistingProperty(this, offset);
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1334,15 +1310,13 @@
</span><span class="cx">         Butterfly* newButterfly = butterfly();
</span><span class="cx">         if (this-&gt;structure()-&gt;putWillGrowOutOfLineStorage())
</span><span class="cx">             newButterfly = growOutOfLineStorage(vm, this-&gt;structure()-&gt;outOfLineCapacity(), this-&gt;structure()-&gt;suggestedNewOutOfLineStorageCapacity());
</span><del>-        offset = this-&gt;structure()-&gt;addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction);
</del><ins>+        offset = this-&gt;structure()-&gt;addPropertyWithoutTransition(vm, propertyName, attributes);
</ins><span class="cx">         setStructureAndButterfly(vm, this-&gt;structure(), newButterfly);
</span><span class="cx"> 
</span><span class="cx">         validateOffset(offset);
</span><span class="cx">         ASSERT(this-&gt;structure()-&gt;isValidOffset(offset));
</span><span class="cx">         putDirect(vm, offset, value);
</span><del>-        // See comment on setNewProperty call below.
-        if (!specificFunction)
-            slot.setNewProperty(this, offset);
</del><ins>+        slot.setNewProperty(this, offset);
</ins><span class="cx">         if (attributes &amp; ReadOnly)
</span><span class="cx">             this-&gt;structure()-&gt;setContainsReadOnlyProperties();
</span><span class="cx">         return true;
</span><span class="lines">@@ -1350,7 +1324,7 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset offset;
</span><span class="cx">     size_t currentCapacity = this-&gt;structure()-&gt;outOfLineCapacity();
</span><del>-    if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this-&gt;structure(), propertyName, attributes, specificFunction, offset)) {
</del><ins>+    if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this-&gt;structure(), propertyName, attributes, offset)) {
</ins><span class="cx">         DeferGC deferGC(vm.heap);
</span><span class="cx">         Butterfly* newButterfly = butterfly();
</span><span class="cx">         if (currentCapacity != structure-&gt;outOfLineCapacity()) {
</span><span class="lines">@@ -1362,40 +1336,17 @@
</span><span class="cx">         ASSERT(structure-&gt;isValidOffset(offset));
</span><span class="cx">         setStructureAndButterfly(vm, structure, newButterfly);
</span><span class="cx">         putDirect(vm, offset, value);
</span><del>-        // This is a new property; transitions with specific values are not currently cachable,
-        // so leave the slot in an uncachable state.
-        if (!specificFunction)
-            slot.setNewProperty(this, offset);
</del><ins>+        slot.setNewProperty(this, offset);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     unsigned currentAttributes;
</span><del>-    JSCell* currentSpecificFunction;
-    offset = structure-&gt;get(vm, propertyName, currentAttributes, currentSpecificFunction);
</del><ins>+    offset = structure-&gt;get(vm, propertyName, currentAttributes);
</ins><span class="cx">     if (offset != invalidOffset) {
</span><span class="cx">         if ((mode == PutModePut) &amp;&amp; currentAttributes &amp; ReadOnly)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        // There are three possibilities here:
-        //  (1) There is an existing specific value set, and we're overwriting with *the same value*.
-        //       * Do nothing - no need to despecify, but that means we can't cache (a cached
-        //         put could write a different value). Leave the slot in an uncachable state.
-        //  (2) There is a specific value currently set, but we're writing a different value.
-        //       * First, we have to despecify.  Having done so, this is now a regular slot
-        //         with no specific value, so go ahead &amp; cache like normal.
-        //  (3) Normal case, there is no specific value set.
-        //       * Go ahead &amp; cache like normal.
-        if (currentSpecificFunction) {
-            // case (1) Do the put, then return leaving the slot uncachable.
-            if (specificFunction == currentSpecificFunction) {
-                putDirect(vm, offset, value);
-                return true;
-            }
-            // case (2) Despecify, fall through to (3).
-            setStructure(vm, Structure::despecifyFunctionTransition(vm, structure, propertyName));
-        }
-
-        // case (3) set the slot, do the put, return.
</del><ins>+        structure-&gt;didReplaceProperty(offset);
</ins><span class="cx">         slot.setExistingProperty(this, offset);
</span><span class="cx">         putDirect(vm, offset, value);
</span><span class="cx">         return true;
</span><span class="lines">@@ -1404,17 +1355,14 @@
</span><span class="cx">     if ((mode == PutModePut) &amp;&amp; !isExtensible())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, specificFunction, offset, slot.context());
</del><ins>+    structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, offset, slot.context());
</ins><span class="cx">     
</span><span class="cx">     validateOffset(offset);
</span><span class="cx">     ASSERT(structure-&gt;isValidOffset(offset));
</span><span class="cx">     setStructureAndReallocateStorageIfNecessary(vm, structure);
</span><span class="cx"> 
</span><span class="cx">     putDirect(vm, offset, value);
</span><del>-    // This is a new property; transitions with specific values are not currently cachable,
-    // so leave the slot in an uncachable state.
-    if (!specificFunction)
-        slot.setNewProperty(this, offset);
</del><ins>+    slot.setNewProperty(this, offset);
</ins><span class="cx">     if (attributes &amp; ReadOnly)
</span><span class="cx">         structure-&gt;setContainsReadOnlyProperties();
</span><span class="cx">     return true;
</span><span class="lines">@@ -1447,20 +1395,20 @@
</span><span class="cx">     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
</span><span class="cx">     ASSERT(!structure()-&gt;hasGetterSetterProperties());
</span><span class="cx"> 
</span><del>-    return putDirectInternal&lt;PutModePut&gt;(vm, propertyName, value, 0, slot, getCallableObject(value));
</del><ins>+    return putDirectInternal&lt;PutModePut&gt;(vm, propertyName, value, 0, slot);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void JSObject::putDirect(VM&amp; vm, PropertyName propertyName, JSValue value, unsigned attributes)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!value.isGetterSetter() &amp;&amp; !(attributes &amp; Accessor));
</span><span class="cx">     PutPropertySlot slot(this);
</span><del>-    putDirectInternal&lt;PutModeDefineOwnProperty&gt;(vm, propertyName, value, attributes, slot, getCallableObject(value));
</del><ins>+    putDirectInternal&lt;PutModeDefineOwnProperty&gt;(vm, propertyName, value, attributes, slot);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void JSObject::putDirect(VM&amp; vm, PropertyName propertyName, JSValue value, PutPropertySlot&amp; slot)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!value.isGetterSetter());
</span><del>-    putDirectInternal&lt;PutModeDefineOwnProperty&gt;(vm, propertyName, value, 0, slot, getCallableObject(value));
</del><ins>+    putDirectInternal&lt;PutModeDefineOwnProperty&gt;(vm, propertyName, value, 0, slot);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void JSObject::putDirectWithoutTransition(VM&amp; vm, PropertyName propertyName, JSValue value, unsigned attributes)
</span><span class="lines">@@ -1470,7 +1418,7 @@
</span><span class="cx">     Butterfly* newButterfly = m_butterfly.get();
</span><span class="cx">     if (structure()-&gt;putWillGrowOutOfLineStorage())
</span><span class="cx">         newButterfly = growOutOfLineStorage(vm, structure()-&gt;outOfLineCapacity(), structure()-&gt;suggestedNewOutOfLineStorageCapacity());
</span><del>-    PropertyOffset offset = structure()-&gt;addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value));
</del><ins>+    PropertyOffset offset = structure()-&gt;addPropertyWithoutTransition(vm, propertyName, attributes);
</ins><span class="cx">     setStructureAndButterfly(vm, structure(), newButterfly);
</span><span class="cx">     putDirect(vm, offset, value);
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeJSScopecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/JSScope.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/JSScope.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/JSScope.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -99,8 +99,19 @@
</span><span class="cx">             op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0);
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><del>-
-        op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject-&gt;structure(), 0, 0, slot.cachedOffset());
</del><ins>+        
+        WatchpointState state = globalObject-&gt;structure()-&gt;ensurePropertyReplacementWatchpointSet(exec-&gt;vm(), slot.cachedOffset())-&gt;state();
+        if (state == IsWatched &amp;&amp; getOrPut == Put) {
+            // The field exists, but because the replacement watchpoint is still intact. This is
+            // kind of dangerous. We have two options:
+            // 1) Invalidate the watchpoint set. That would work, but it's possible that this code
+            //    path never executes - in which case this would be unwise.
+            // 2) Have the invalidation happen at run-time. All we have to do is leave the code
+            //    uncached. The only downside is slightly more work when this does execute.
+            // We go with option (2) here because it seems less evil.
+            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0);
+        } else
+            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject-&gt;structure(), 0, 0, slot.cachedOffset());
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimePropertyMapHashTableh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/PropertyMapHashTable.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/PropertyMapHashTable.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/PropertyMapHashTable.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -76,13 +76,11 @@
</span><span class="cx">     StringImpl* key;
</span><span class="cx">     PropertyOffset offset;
</span><span class="cx">     unsigned attributes;
</span><del>-    WriteBarrier&lt;JSCell&gt; specificValue;
</del><span class="cx"> 
</span><del>-    PropertyMapEntry(VM&amp; vm, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue)
</del><ins>+    PropertyMapEntry(StringImpl* key, PropertyOffset offset, unsigned attributes)
</ins><span class="cx">         : key(key)
</span><span class="cx">         , offset(offset)
</span><span class="cx">         , attributes(attributes)
</span><del>-        , specificValue(vm, owner, specificValue, WriteBarrier&lt;JSCell&gt;::MayBeNull)
</del><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="lines">@@ -141,8 +139,6 @@
</span><span class="cx">         return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static void visitChildren(JSCell*, SlotVisitor&amp;);
-
</del><span class="cx">     typedef StringImpl* KeyType;
</span><span class="cx">     typedef PropertyMapEntry ValueType;
</span><span class="cx"> 
</span><span class="lines">@@ -157,8 +153,8 @@
</span><span class="cx"> 
</span><span class="cx">     // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
</span><span class="cx">     static PropertyTable* create(VM&amp;, unsigned initialCapacity);
</span><del>-    static PropertyTable* clone(VM&amp;, JSCell* owner, const PropertyTable&amp;);
-    static PropertyTable* clone(VM&amp;, JSCell* owner, unsigned initialCapacity, const PropertyTable&amp;);
</del><ins>+    static PropertyTable* clone(VM&amp;, const PropertyTable&amp;);
+    static PropertyTable* clone(VM&amp;, unsigned initialCapacity, const PropertyTable&amp;);
</ins><span class="cx">     ~PropertyTable();
</span><span class="cx"> 
</span><span class="cx">     // Ordered iteration methods.
</span><span class="lines">@@ -196,7 +192,7 @@
</span><span class="cx">     PropertyOffset nextOffset(PropertyOffset inlineCapacity);
</span><span class="cx"> 
</span><span class="cx">     // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
</span><del>-    PropertyTable* copy(VM&amp;, JSCell* owner, unsigned newCapacity);
</del><ins>+    PropertyTable* copy(VM&amp;, unsigned newCapacity);
</ins><span class="cx"> 
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     size_t sizeInMemory();
</span><span class="lines">@@ -204,12 +200,12 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> protected:
</span><del>-    static const unsigned StructureFlags = OverridesVisitChildren | StructureIsImmortal;
</del><ins>+    static const unsigned StructureFlags = StructureIsImmortal;
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     PropertyTable(VM&amp;, unsigned initialCapacity);
</span><del>-    PropertyTable(VM&amp;, JSCell*, const PropertyTable&amp;);
-    PropertyTable(VM&amp;, JSCell*, unsigned initialCapacity, const PropertyTable&amp;);
</del><ins>+    PropertyTable(VM&amp;, const PropertyTable&amp;);
+    PropertyTable(VM&amp;, unsigned initialCapacity, const PropertyTable&amp;);
</ins><span class="cx"> 
</span><span class="cx">     PropertyTable(const PropertyTable&amp;);
</span><span class="cx">     // Used to insert a value known not to be in the table, and where we know capacity to be available.
</span><span class="lines">@@ -494,15 +490,15 @@
</span><span class="cx">     return offsetForPropertyNumber(size(), inlineCapacity);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline PropertyTable* PropertyTable::copy(VM&amp; vm, JSCell* owner, unsigned newCapacity)
</del><ins>+inline PropertyTable* PropertyTable::copy(VM&amp; vm, unsigned newCapacity)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(newCapacity &gt;= m_keyCount);
</span><span class="cx"> 
</span><span class="cx">     // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it,
</span><span class="cx">     // save rehashing all keys.
</span><span class="cx">     if (sizeForCapacity(newCapacity) == m_indexSize)
</span><del>-        return PropertyTable::clone(vm, owner, *this);
-    return PropertyTable::clone(vm, owner, newCapacity, *this);
</del><ins>+        return PropertyTable::clone(vm, *this);
+    return PropertyTable::clone(vm, newCapacity, *this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #ifndef NDEBUG
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimePropertyTablecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/PropertyTable.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/PropertyTable.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/PropertyTable.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -44,16 +44,16 @@
</span><span class="cx">     return table;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyTable* PropertyTable::clone(VM&amp; vm, JSCell* owner, const PropertyTable&amp; other)
</del><ins>+PropertyTable* PropertyTable::clone(VM&amp; vm, const PropertyTable&amp; other)
</ins><span class="cx"> {
</span><del>-    PropertyTable* table = new (NotNull, allocateCell&lt;PropertyTable&gt;(vm.heap)) PropertyTable(vm, owner, other);
</del><ins>+    PropertyTable* table = new (NotNull, allocateCell&lt;PropertyTable&gt;(vm.heap)) PropertyTable(vm, other);
</ins><span class="cx">     table-&gt;finishCreation(vm);
</span><span class="cx">     return table;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyTable* PropertyTable::clone(VM&amp; vm, JSCell* owner, unsigned initialCapacity, const PropertyTable&amp; other)
</del><ins>+PropertyTable* PropertyTable::clone(VM&amp; vm, unsigned initialCapacity, const PropertyTable&amp; other)
</ins><span class="cx"> {
</span><del>-    PropertyTable* table = new (NotNull, allocateCell&lt;PropertyTable&gt;(vm.heap)) PropertyTable(vm, owner, initialCapacity, other);
</del><ins>+    PropertyTable* table = new (NotNull, allocateCell&lt;PropertyTable&gt;(vm.heap)) PropertyTable(vm, initialCapacity, other);
</ins><span class="cx">     table-&gt;finishCreation(vm);
</span><span class="cx">     return table;
</span><span class="cx"> }
</span><span class="lines">@@ -69,7 +69,7 @@
</span><span class="cx">     ASSERT(isPowerOf2(m_indexSize));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyTable::PropertyTable(VM&amp; vm, JSCell* owner, const PropertyTable&amp; other)
</del><ins>+PropertyTable::PropertyTable(VM&amp; vm, const PropertyTable&amp; other)
</ins><span class="cx">     : JSCell(vm, vm.propertyTableStructure.get())
</span><span class="cx">     , m_indexSize(other.m_indexSize)
</span><span class="cx">     , m_indexMask(other.m_indexMask)
</span><span class="lines">@@ -82,10 +82,8 @@
</span><span class="cx">     memcpy(m_index, other.m_index, dataSize());
</span><span class="cx"> 
</span><span class="cx">     iterator end = this-&gt;end();
</span><del>-    for (iterator iter = begin(); iter != end; ++iter) {
</del><ins>+    for (iterator iter = begin(); iter != end; ++iter)
</ins><span class="cx">         iter-&gt;key-&gt;ref();
</span><del>-        vm.heap.writeBarrier(owner, iter-&gt;specificValue.get());
-    }
</del><span class="cx"> 
</span><span class="cx">     // Copy the m_deletedOffsets vector.
</span><span class="cx">     Vector&lt;PropertyOffset&gt;* otherDeletedOffsets = other.m_deletedOffsets.get();
</span><span class="lines">@@ -93,7 +91,7 @@
</span><span class="cx">         m_deletedOffsets = adoptPtr(new Vector&lt;PropertyOffset&gt;(*otherDeletedOffsets));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyTable::PropertyTable(VM&amp; vm, JSCell* owner, unsigned initialCapacity, const PropertyTable&amp; other)
</del><ins>+PropertyTable::PropertyTable(VM&amp; vm, unsigned initialCapacity, const PropertyTable&amp; other)
</ins><span class="cx">     : JSCell(vm, vm.propertyTableStructure.get())
</span><span class="cx">     , m_indexSize(sizeForCapacity(initialCapacity))
</span><span class="cx">     , m_indexMask(m_indexSize - 1)
</span><span class="lines">@@ -109,7 +107,6 @@
</span><span class="cx">         ASSERT(canInsert());
</span><span class="cx">         reinsert(*iter);
</span><span class="cx">         iter-&gt;key-&gt;ref();
</span><del>-        vm.heap.writeBarrier(owner, iter-&gt;specificValue.get());
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Copy the m_deletedOffsets vector.
</span><span class="lines">@@ -132,17 +129,4 @@
</span><span class="cx">     fastFree(m_index);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void PropertyTable::visitChildren(JSCell* cell, SlotVisitor&amp; visitor)
-{
-    PropertyTable* thisObject = jsCast&lt;PropertyTable*&gt;(cell);
-    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-    ASSERT(thisObject-&gt;structure()-&gt;typeInfo().overridesVisitChildren());
-
-    JSCell::visitChildren(thisObject, visitor);
-
-    PropertyTable::iterator end = thisObject-&gt;end();
-    for (PropertyTable::iterator ptr = thisObject-&gt;begin(); ptr != end; ++ptr)
-        visitor.append(&amp;ptr-&gt;specificValue);
</del><span class="cx"> }
</span><del>-
-}
</del></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/Structure.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/Structure.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/Structure.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -173,7 +173,6 @@
</span><span class="cx">     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo-&gt;hasStaticSetterOrReadonlyProperties(vm));
</span><span class="cx">     setHasNonEnumerableProperties(false);
</span><span class="cx">     setAttributesInPrevious(0);
</span><del>-    setSpecificFunctionThrashCount(0);
</del><span class="cx">     setPreventExtensions(false);
</span><span class="cx">     setDidTransition(false);
</span><span class="cx">     setStaticFunctionsReified(false);
</span><span class="lines">@@ -203,7 +202,6 @@
</span><span class="cx">     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo-&gt;hasStaticSetterOrReadonlyProperties(vm));
</span><span class="cx">     setHasNonEnumerableProperties(false);
</span><span class="cx">     setAttributesInPrevious(0);
</span><del>-    setSpecificFunctionThrashCount(0);
</del><span class="cx">     setPreventExtensions(false);
</span><span class="cx">     setDidTransition(false);
</span><span class="cx">     setStaticFunctionsReified(false);
</span><span class="lines">@@ -232,7 +230,6 @@
</span><span class="cx">     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous-&gt;hasReadOnlyOrGetterSetterPropertiesExcludingProto());
</span><span class="cx">     setHasNonEnumerableProperties(previous-&gt;hasNonEnumerableProperties());
</span><span class="cx">     setAttributesInPrevious(0);
</span><del>-    setSpecificFunctionThrashCount(previous-&gt;specificFunctionThrashCount());
</del><span class="cx">     setPreventExtensions(previous-&gt;preventExtensions());
</span><span class="cx">     setDidTransition(true);
</span><span class="cx">     setStaticFunctionsReified(previous-&gt;staticFunctionsReified());
</span><span class="lines">@@ -300,7 +297,7 @@
</span><span class="cx">     findStructuresAndMapForMaterialization(structures, structure, table);
</span><span class="cx">     
</span><span class="cx">     if (table) {
</span><del>-        table = table-&gt;copy(vm, structure, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
</del><ins>+        table = table-&gt;copy(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
</ins><span class="cx">         structure-&gt;m_lock.unlock();
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -317,7 +314,7 @@
</span><span class="cx">         structure = structures[i];
</span><span class="cx">         if (!structure-&gt;m_nameInPrevious)
</span><span class="cx">             continue;
</span><del>-        PropertyMapEntry entry(vm, this, structure-&gt;m_nameInPrevious.get(), structure-&gt;m_offset, structure-&gt;attributesInPrevious(), structure-&gt;m_specificValueInPrevious.get());
</del><ins>+        PropertyMapEntry entry(structure-&gt;m_nameInPrevious.get(), structure-&gt;m_offset, structure-&gt;attributesInPrevious());
</ins><span class="cx">         propertyTable()-&gt;add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -336,30 +333,12 @@
</span><span class="cx">     return nextOutOfLineStorageCapacity(outOfLineCapacity());
</span><span class="cx"> }
</span><span class="cx">  
</span><del>-void Structure::despecifyDictionaryFunction(VM&amp; vm, PropertyName propertyName)
</del><ins>+Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, PropertyOffset&amp; offset)
</ins><span class="cx"> {
</span><del>-    StringImpl* rep = propertyName.uid();
-
-    DeferGC deferGC(vm.heap);
-    materializePropertyMapIfNecessary(vm, deferGC);
-
-    ASSERT(isDictionary());
-    ASSERT(propertyTable());
-
-    PropertyMapEntry* entry = propertyTable()-&gt;get(rep);
-    ASSERT(entry);
-    entry-&gt;specificValue.clear();
-}
-
-Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&amp; offset)
-{
</del><span class="cx">     ASSERT(!structure-&gt;isDictionary());
</span><span class="cx">     ASSERT(structure-&gt;isObject());
</span><span class="cx"> 
</span><span class="cx">     if (Structure* existingTransition = structure-&gt;m_transitionTable.get(uid, attributes)) {
</span><del>-        JSCell* specificValueInPrevious = existingTransition-&gt;m_specificValueInPrevious.get();
-        if (specificValueInPrevious &amp;&amp; specificValueInPrevious != specificValue)
-            return 0;
</del><span class="cx">         validateOffset(existingTransition-&gt;m_offset, existingTransition-&gt;inlineCapacity());
</span><span class="cx">         offset = existingTransition-&gt;m_offset;
</span><span class="cx">         return existingTransition;
</span><span class="lines">@@ -368,16 +347,16 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&amp; offset)
</del><ins>+Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset&amp; offset)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!isCompilationThread());
</span><del>-    return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, specificValue, offset);
</del><ins>+    return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, offset);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&amp; offset)
</del><ins>+Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, PropertyOffset&amp; offset)
</ins><span class="cx"> {
</span><span class="cx">     ConcurrentJITLocker locker(structure-&gt;m_lock);
</span><del>-    return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, specificValue, offset);
</del><ins>+    return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, offset);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
</span><span class="lines">@@ -432,25 +411,12 @@
</span><span class="cx">     return AllocateArrayStorage;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Structure* Structure::addPropertyTransition(VM&amp; vm, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&amp; offset, PutPropertySlot::Context context)
</del><ins>+Structure* Structure::addPropertyTransition(VM&amp; vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset&amp; offset, PutPropertySlot::Context context)
</ins><span class="cx"> {
</span><del>-    // If we have a specific function, we may have got to this point if there is
-    // already a transition with the correct property name and attributes, but
-    // specialized to a different function.  In this case we just want to give up
-    // and despecialize the transition.
-    // In this case we clear the value of specificFunction which will result
-    // in us adding a non-specific transition, and any subsequent lookup in
-    // Structure::addPropertyTransitionToExistingStructure will just use that.
-    if (specificValue &amp;&amp; structure-&gt;m_transitionTable.contains(propertyName.uid(), attributes))
-        specificValue = 0;
-
</del><span class="cx">     ASSERT(!structure-&gt;isDictionary());
</span><span class="cx">     ASSERT(structure-&gt;isObject());
</span><del>-    ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
</del><ins>+    ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset));
</ins><span class="cx">     
</span><del>-    if (structure-&gt;specificFunctionThrashCount() == maxSpecificFunctionThrashCount)
-        specificValue = 0;
-
</del><span class="cx">     int maxTransitionLength;
</span><span class="cx">     if (context == PutPropertySlot::PutById)
</span><span class="cx">         maxTransitionLength = s_maxTransitionLengthForNonEvalPutById;
</span><span class="lines">@@ -459,7 +425,7 @@
</span><span class="cx">     if (structure-&gt;transitionCount() &gt; maxTransitionLength) {
</span><span class="cx">         Structure* transition = toCacheableDictionaryTransition(vm, structure);
</span><span class="cx">         ASSERT(structure != transition);
</span><del>-        offset = transition-&gt;putSpecificValue(vm, propertyName, attributes, specificValue);
</del><ins>+        offset = transition-&gt;add(vm, propertyName, attributes);
</ins><span class="cx">         return transition;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -469,11 +435,10 @@
</span><span class="cx">     transition-&gt;setPreviousID(vm, transition, structure);
</span><span class="cx">     transition-&gt;m_nameInPrevious = propertyName.uid();
</span><span class="cx">     transition-&gt;setAttributesInPrevious(attributes);
</span><del>-    transition-&gt;m_specificValueInPrevious.setMayBeNull(vm, transition, specificValue);
-    transition-&gt;propertyTable().set(vm, transition, structure-&gt;takePropertyTableOrCloneIfPinned(vm, transition));
</del><ins>+    transition-&gt;propertyTable().set(vm, transition, structure-&gt;takePropertyTableOrCloneIfPinned(vm));
</ins><span class="cx">     transition-&gt;m_offset = structure-&gt;m_offset;
</span><span class="cx"> 
</span><del>-    offset = transition-&gt;putSpecificValue(vm, propertyName, attributes, specificValue);
</del><ins>+    offset = transition-&gt;add(vm, propertyName, attributes);
</ins><span class="cx"> 
</span><span class="cx">     checkOffset(transition-&gt;m_offset, transition-&gt;inlineCapacity());
</span><span class="cx">     {
</span><span class="lines">@@ -505,7 +470,7 @@
</span><span class="cx"> 
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     structure-&gt;materializePropertyMapIfNecessary(vm, deferGC);
</span><del>-    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm, transition));
</del><ins>+    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm));
</ins><span class="cx">     transition-&gt;m_offset = structure-&gt;m_offset;
</span><span class="cx">     transition-&gt;pin();
</span><span class="cx"> 
</span><span class="lines">@@ -513,30 +478,6 @@
</span><span class="cx">     return transition;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Structure* Structure::despecifyFunctionTransition(VM&amp; vm, Structure* structure, PropertyName replaceFunction)
-{
-    ASSERT(structure-&gt;specificFunctionThrashCount() &lt; maxSpecificFunctionThrashCount);
-    Structure* transition = create(vm, structure);
-
-    transition-&gt;setSpecificFunctionThrashCount(transition-&gt;specificFunctionThrashCount() + 1);
-
-    DeferGC deferGC(vm.heap);
-    structure-&gt;materializePropertyMapIfNecessary(vm, deferGC);
-    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm, transition));
-    transition-&gt;m_offset = structure-&gt;m_offset;
-    transition-&gt;pin();
-
-    if (transition-&gt;specificFunctionThrashCount() == maxSpecificFunctionThrashCount)
-        transition-&gt;despecifyAllFunctions(vm);
-    else {
-        bool removed = transition-&gt;despecifyFunction(vm, replaceFunction);
-        ASSERT_UNUSED(removed, removed);
-    }
-
-    transition-&gt;checkOffsetConsistency();
-    return transition;
-}
-
</del><span class="cx"> Structure* Structure::attributeChangeTransition(VM&amp; vm, Structure* structure, PropertyName propertyName, unsigned attributes)
</span><span class="cx"> {
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="lines">@@ -544,7 +485,7 @@
</span><span class="cx">         Structure* transition = create(vm, structure);
</span><span class="cx"> 
</span><span class="cx">         structure-&gt;materializePropertyMapIfNecessary(vm, deferGC);
</span><del>-        transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm, transition));
</del><ins>+        transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm));
</ins><span class="cx">         transition-&gt;m_offset = structure-&gt;m_offset;
</span><span class="cx">         transition-&gt;pin();
</span><span class="cx">         
</span><span class="lines">@@ -568,7 +509,7 @@
</span><span class="cx"> 
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     structure-&gt;materializePropertyMapIfNecessary(vm, deferGC);
</span><del>-    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm, transition));
</del><ins>+    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm));
</ins><span class="cx">     transition-&gt;m_offset = structure-&gt;m_offset;
</span><span class="cx">     transition-&gt;setDictionaryKind(kind);
</span><span class="cx">     transition-&gt;pin();
</span><span class="lines">@@ -631,7 +572,7 @@
</span><span class="cx"> 
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     structure-&gt;materializePropertyMapIfNecessary(vm, deferGC);
</span><del>-    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm, transition));
</del><ins>+    transition-&gt;propertyTable().set(vm, transition, structure-&gt;copyPropertyTableForPinning(vm));
</ins><span class="cx">     transition-&gt;m_offset = structure-&gt;m_offset;
</span><span class="cx">     transition-&gt;setPreventExtensions(true);
</span><span class="cx">     transition-&gt;pin();
</span><span class="lines">@@ -640,13 +581,13 @@
</span><span class="cx">     return transition;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM&amp; vm, Structure* owner)
</del><ins>+PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM&amp; vm)
</ins><span class="cx"> {
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     materializePropertyMapIfNecessaryForPinning(vm, deferGC);
</span><span class="cx">     
</span><span class="cx">     if (isPinnedPropertyTable())
</span><del>-        return propertyTable()-&gt;copy(vm, owner, propertyTable()-&gt;size() + 1);
</del><ins>+        return propertyTable()-&gt;copy(vm, propertyTable()-&gt;size() + 1);
</ins><span class="cx">     
</span><span class="cx">     // Hold the lock while stealing the table - so that getConcurrently() on another thread
</span><span class="cx">     // will either have to bypass this structure, or will get to use the property table
</span><span class="lines">@@ -682,7 +623,7 @@
</span><span class="cx">     transition-&gt;setPreviousID(vm, transition, structure);
</span><span class="cx">     transition-&gt;setAttributesInPrevious(attributes);
</span><span class="cx">     transition-&gt;m_blob.setIndexingType(indexingType);
</span><del>-    transition-&gt;propertyTable().set(vm, transition, structure-&gt;takePropertyTableOrCloneIfPinned(vm, transition));
</del><ins>+    transition-&gt;propertyTable().set(vm, transition, structure-&gt;takePropertyTableOrCloneIfPinned(vm));
</ins><span class="cx">     transition-&gt;m_offset = structure-&gt;m_offset;
</span><span class="cx">     checkOffset(transition-&gt;m_offset, transition-&gt;inlineCapacity());
</span><span class="cx">     
</span><span class="lines">@@ -773,19 +714,16 @@
</span><span class="cx">     return this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyOffset Structure::addPropertyWithoutTransition(VM&amp; vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
</del><ins>+PropertyOffset Structure::addPropertyWithoutTransition(VM&amp; vm, PropertyName propertyName, unsigned attributes)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!enumerationCache());
</span><span class="cx"> 
</span><del>-    if (specificFunctionThrashCount() == maxSpecificFunctionThrashCount)
-        specificValue = 0;
-
</del><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     materializePropertyMapIfNecessaryForPinning(vm, deferGC);
</span><span class="cx">     
</span><span class="cx">     pin();
</span><span class="cx"> 
</span><del>-    return putSpecificValue(vm, propertyName, attributes, specificValue);
</del><ins>+    return add(vm, propertyName, attributes);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PropertyOffset Structure::removePropertyWithoutTransition(VM&amp; vm, PropertyName propertyName)
</span><span class="lines">@@ -812,11 +750,57 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!hasRareData());
</span><span class="cx">     StructureRareData* rareData = StructureRareData::create(vm, previous());
</span><ins>+    WTF::storeStoreFence();
</ins><span class="cx">     m_previousOrRareData.set(vm, this, rareData);
</span><ins>+    WTF::storeStoreFence();
</ins><span class="cx">     setHasRareData(true);
</span><span class="cx">     ASSERT(hasRareData());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+WatchpointSet* Structure::ensurePropertyReplacementWatchpointSet(VM&amp; vm, PropertyOffset offset)
+{
+    ASSERT(!isUncacheableDictionary());
+    
+    if (!hasRareData())
+        allocateRareData(vm);
+    ConcurrentJITLocker locker(m_lock);
+    StructureRareData* rareData = this-&gt;rareData();
+    if (!rareData-&gt;m_replacementWatchpointSets) {
+        rareData-&gt;m_replacementWatchpointSets =
+            std::make_unique&lt;StructureRareData::PropertyWatchpointMap&gt;();
+        WTF::storeStoreFence();
+    }
+    auto result = rareData-&gt;m_replacementWatchpointSets-&gt;add(offset, nullptr);
+    if (result.isNewEntry)
+        result.iterator-&gt;value = adoptRef(new WatchpointSet(IsWatched));
+    return result.iterator-&gt;value.get();
+}
+
+void Structure::startWatchingPropertyForReplacements(VM&amp; vm, PropertyName propertyName)
+{
+    ASSERT(!isUncacheableDictionary());
+    
+    PropertyOffset offset = get(vm, propertyName);
+    if (!JSC::isValidOffset(offset))
+        return;
+    
+    startWatchingPropertyForReplacements(vm, offset);
+}
+
+void Structure::didCachePropertyReplacement(VM&amp; vm, PropertyOffset offset)
+{
+    ensurePropertyReplacementWatchpointSet(vm, offset)-&gt;fireAll(&quot;Did cache property replacement&quot;);
+}
+
+void Structure::startWatchingInternalProperties(VM&amp; vm)
+{
+    if (!isUncacheableDictionary()) {
+        startWatchingPropertyForReplacements(vm, vm.propertyNames-&gt;toString);
+        startWatchingPropertyForReplacements(vm, vm.propertyNames-&gt;valueOf);
+    }
+    setDidWatchInternalProperties(true);
+}
+
</ins><span class="cx"> #if DUMP_PROPERTYMAP_STATS
</span><span class="cx"> 
</span><span class="cx"> struct PropertyMapStatisticsExitLogger {
</span><span class="lines">@@ -845,21 +829,21 @@
</span><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-PropertyTable* Structure::copyPropertyTable(VM&amp; vm, Structure* owner)
</del><ins>+PropertyTable* Structure::copyPropertyTable(VM&amp; vm)
</ins><span class="cx"> {
</span><span class="cx">     if (!propertyTable())
</span><span class="cx">         return 0;
</span><del>-    return PropertyTable::clone(vm, owner, *propertyTable().get());
</del><ins>+    return PropertyTable::clone(vm, *propertyTable().get());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyTable* Structure::copyPropertyTableForPinning(VM&amp; vm, Structure* owner)
</del><ins>+PropertyTable* Structure::copyPropertyTableForPinning(VM&amp; vm)
</ins><span class="cx"> {
</span><span class="cx">     if (propertyTable())
</span><del>-        return PropertyTable::clone(vm, owner, *propertyTable().get());
</del><ins>+        return PropertyTable::clone(vm, *propertyTable().get());
</ins><span class="cx">     return PropertyTable::create(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyOffset Structure::getConcurrently(VM&amp;, StringImpl* uid, unsigned&amp; attributes, JSCell*&amp; specificValue)
</del><ins>+PropertyOffset Structure::getConcurrently(VM&amp;, StringImpl* uid, unsigned&amp; attributes)
</ins><span class="cx"> {
</span><span class="cx">     Vector&lt;Structure*, 8&gt; structures;
</span><span class="cx">     Structure* structure;
</span><span class="lines">@@ -871,7 +855,6 @@
</span><span class="cx">         PropertyMapEntry* entry = table-&gt;get(uid);
</span><span class="cx">         if (entry) {
</span><span class="cx">             attributes = entry-&gt;attributes;
</span><del>-            specificValue = entry-&gt;specificValue.get();
</del><span class="cx">             PropertyOffset result = entry-&gt;offset;
</span><span class="cx">             structure-&gt;m_lock.unlock();
</span><span class="cx">             return result;
</span><span class="lines">@@ -885,14 +868,13 @@
</span><span class="cx">             continue;
</span><span class="cx">         
</span><span class="cx">         attributes = structure-&gt;attributesInPrevious();
</span><del>-        specificValue = structure-&gt;m_specificValueInPrevious.get();
</del><span class="cx">         return structure-&gt;m_offset;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     return invalidOffset;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PropertyOffset Structure::get(VM&amp; vm, PropertyName propertyName, unsigned&amp; attributes, JSCell*&amp; specificValue)
</del><ins>+PropertyOffset Structure::get(VM&amp; vm, PropertyName propertyName, unsigned&amp; attributes)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!isCompilationThread());
</span><span class="cx">     ASSERT(structure()-&gt;classInfo() == info());
</span><span class="lines">@@ -907,42 +889,15 @@
</span><span class="cx">         return invalidOffset;
</span><span class="cx"> 
</span><span class="cx">     attributes = entry-&gt;attributes;
</span><del>-    specificValue = entry-&gt;specificValue.get();
</del><span class="cx">     return entry-&gt;offset;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool Structure::despecifyFunction(VM&amp; vm, PropertyName propertyName)
</del><ins>+PropertyOffset Structure::add(VM&amp; vm, PropertyName propertyName, unsigned attributes)
</ins><span class="cx"> {
</span><del>-    DeferGC deferGC(vm.heap);
-    materializePropertyMapIfNecessary(vm, deferGC);
-    if (!propertyTable())
-        return false;
-
-    PropertyMapEntry* entry = propertyTable()-&gt;get(propertyName.uid());
-    if (!entry)
-        return false;
-
-    ASSERT(entry-&gt;specificValue);
-    entry-&gt;specificValue.clear();
-    return true;
-}
-
-void Structure::despecifyAllFunctions(VM&amp; vm)
-{
-    DeferGC deferGC(vm.heap);
-    materializePropertyMapIfNecessary(vm, deferGC);
-    if (!propertyTable())
-        return;
-
-    PropertyTable::iterator end = propertyTable()-&gt;end();
-    for (PropertyTable::iterator iter = propertyTable()-&gt;begin(); iter != end; ++iter)
-        iter-&gt;specificValue.clear();
-}
-
-PropertyOffset Structure::putSpecificValue(VM&amp; vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
-{
</del><span class="cx">     GCSafeConcurrentJITLocker locker(m_lock, vm.heap);
</span><span class="cx">     
</span><ins>+    setDidWatchInternalProperties(false);
+    
</ins><span class="cx">     ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
</span><span class="cx"> 
</span><span class="cx">     checkConsistency();
</span><span class="lines">@@ -956,7 +911,7 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset newOffset = propertyTable()-&gt;nextOffset(m_inlineCapacity);
</span><span class="cx"> 
</span><del>-    propertyTable()-&gt;add(PropertyMapEntry(vm, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange);
</del><ins>+    propertyTable()-&gt;add(PropertyMapEntry(rep, newOffset, attributes), m_offset, PropertyTable::PropertyOffsetMayChange);
</ins><span class="cx">     
</span><span class="cx">     checkConsistency();
</span><span class="cx">     return newOffset;
</span><span class="lines">@@ -1060,7 +1015,6 @@
</span><span class="cx">         visitor.append(&amp;thisObject-&gt;m_cachedPrototypeChain);
</span><span class="cx">     }
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_previousOrRareData);
</span><del>-    visitor.append(&amp;thisObject-&gt;m_specificValueInPrevious);
</del><span class="cx"> 
</span><span class="cx">     if (thisObject-&gt;isPinnedPropertyTable()) {
</span><span class="cx">         ASSERT(thisObject-&gt;m_propertyTableUnsafe);
</span><span class="lines">@@ -1083,8 +1037,7 @@
</span><span class="cx">         current = prototype.asCell()-&gt;structure(vm);
</span><span class="cx">         
</span><span class="cx">         unsigned attributes;
</span><del>-        JSCell* specificValue;
-        PropertyOffset offset = current-&gt;get(vm, propertyName, attributes, specificValue);
</del><ins>+        PropertyOffset offset = current-&gt;get(vm, propertyName, attributes);
</ins><span class="cx">         if (!JSC::isValidOffset(offset))
</span><span class="cx">             continue;
</span><span class="cx">         
</span><span class="lines">@@ -1143,13 +1096,8 @@
</span><span class="cx">     if (table) {
</span><span class="cx">         PropertyTable::iterator iter = table-&gt;begin();
</span><span class="cx">         PropertyTable::iterator end = table-&gt;end();
</span><del>-        for (; iter != end; ++iter) {
</del><ins>+        for (; iter != end; ++iter)
</ins><span class="cx">             out.print(comma, iter-&gt;key, &quot;:&quot;, static_cast&lt;int&gt;(iter-&gt;offset));
</span><del>-            if (iter-&gt;specificValue) {
-                DumpContext dummyContext;
-                out.print(&quot;=&gt;&quot;, RawPointer(iter-&gt;specificValue.get()));
-            }
-        }
</del><span class="cx">         
</span><span class="cx">         structure-&gt;m_lock.unlock();
</span><span class="cx">     }
</span><span class="lines">@@ -1159,10 +1107,6 @@
</span><span class="cx">         if (!structure-&gt;m_nameInPrevious)
</span><span class="cx">             continue;
</span><span class="cx">         out.print(comma, structure-&gt;m_nameInPrevious.get(), &quot;:&quot;, static_cast&lt;int&gt;(structure-&gt;m_offset));
</span><del>-        if (structure-&gt;m_specificValueInPrevious) {
-            DumpContext dummyContext;
-            out.print(&quot;=&gt;&quot;, RawPointer(structure-&gt;m_specificValueInPrevious.get()));
-        }
</del><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     out.print(&quot;}, &quot;, IndexingTypeDump(indexingType()));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/Structure.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/Structure.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/Structure.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -112,12 +112,11 @@
</span><span class="cx"> 
</span><span class="cx">     static void dumpStatistics();
</span><span class="cx"> 
</span><del>-    JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&amp;, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&amp;, PutPropertySlot::Context = PutPropertySlot::UnknownContext);
-    static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&amp;);
-    JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&amp;);
</del><ins>+    JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&amp;, Structure*, PropertyName, unsigned attributes, PropertyOffset&amp;, PutPropertySlot::Context = PutPropertySlot::UnknownContext);
+    static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, unsigned attributes, PropertyOffset&amp;);
+    JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&amp;);
</ins><span class="cx">     static Structure* removePropertyTransition(VM&amp;, Structure*, PropertyName, PropertyOffset&amp;);
</span><span class="cx">     JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&amp;, Structure*, JSValue prototype);
</span><del>-    JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&amp;, Structure*, PropertyName);
</del><span class="cx">     static Structure* attributeChangeTransition(VM&amp;, Structure*, PropertyName, unsigned attributes);
</span><span class="cx">     static Structure* toCacheableDictionaryTransition(VM&amp;, Structure*);
</span><span class="cx">     static Structure* toUncacheableDictionaryTransition(VM&amp;, Structure*);
</span><span class="lines">@@ -139,7 +138,7 @@
</span><span class="cx">     static void destroy(JSCell*);
</span><span class="cx"> 
</span><span class="cx">     // These should be used with caution.  
</span><del>-    JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&amp;, PropertyName, unsigned attributes, JSCell* specificValue);
</del><ins>+    JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&amp;, PropertyName, unsigned attributes);
</ins><span class="cx">     PropertyOffset removePropertyWithoutTransition(VM&amp;, PropertyName);
</span><span class="cx">     void setPrototypeWithoutTransition(VM&amp; vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
</span><span class="cx">         
</span><span class="lines">@@ -189,8 +188,6 @@
</span><span class="cx">     // Will just the prototype chain intercept this property access?
</span><span class="cx">     bool prototypeChainMayInterceptStoreTo(VM&amp;, PropertyName);
</span><span class="cx">         
</span><del>-    bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
-        
</del><span class="cx">     Structure* previousID() const
</span><span class="cx">     {
</span><span class="cx">         ASSERT(structure()-&gt;classInfo() == info());
</span><span class="lines">@@ -264,10 +261,10 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset get(VM&amp;, PropertyName);
</span><span class="cx">     PropertyOffset get(VM&amp;, const WTF::String&amp; name);
</span><del>-    JS_EXPORT_PRIVATE PropertyOffset get(VM&amp;, PropertyName, unsigned&amp; attributes, JSCell*&amp; specificValue);
</del><ins>+    JS_EXPORT_PRIVATE PropertyOffset get(VM&amp;, PropertyName, unsigned&amp; attributes);
</ins><span class="cx"> 
</span><span class="cx">     PropertyOffset getConcurrently(VM&amp;, StringImpl* uid);
</span><del>-    PropertyOffset getConcurrently(VM&amp;, StringImpl* uid, unsigned&amp; attributes, JSCell*&amp; specificValue);
</del><ins>+    PropertyOffset getConcurrently(VM&amp;, StringImpl* uid, unsigned&amp; attributes);
</ins><span class="cx"> 
</span><span class="cx">     void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__)
</span><span class="cx">     {
</span><span class="lines">@@ -284,9 +281,6 @@
</span><span class="cx">         return !JSC::isValidOffset(m_offset);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&amp;, PropertyName);
-    void disableSpecificFunctionTracking() { setSpecificFunctionThrashCount(maxSpecificFunctionThrashCount); }
-
</del><span class="cx">     void setEnumerationCache(VM&amp;, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
</span><span class="cx">     JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
</span><span class="cx">     void getPropertyNamesFromStructure(VM&amp;, PropertyNameArray&amp;, EnumerationMode);
</span><span class="lines">@@ -365,13 +359,36 @@
</span><span class="cx">         ASSERT(transitionWatchpointSetIsStillValid());
</span><span class="cx">         m_transitionWatchpointSet.add(watchpoint);
</span><span class="cx">     }
</span><del>-        
</del><ins>+    
</ins><span class="cx">     void didTransitionFromThisStructure() const;
</span><span class="cx">     
</span><span class="cx">     InlineWatchpointSet&amp; transitionWatchpointSet() const
</span><span class="cx">     {
</span><span class="cx">         return m_transitionWatchpointSet;
</span><span class="cx">     }
</span><ins>+    
+    WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&amp;, PropertyOffset);
+    void startWatchingPropertyForReplacements(VM&amp; vm, PropertyOffset offset)
+    {
+        ensurePropertyReplacementWatchpointSet(vm, offset);
+    }
+    void startWatchingPropertyForReplacements(VM&amp;, PropertyName);
+    WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset);
+    void didReplaceProperty(PropertyOffset);
+    void didCachePropertyReplacement(VM&amp;, PropertyOffset);
+    
+    void startWatchingInternalPropertiesIfNecessary(VM&amp; vm)
+    {
+        if (LIKELY(didWatchInternalProperties()))
+            return;
+        startWatchingInternalProperties(vm);
+    }
+    
+    void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM&amp; vm)
+    {
+        for (Structure* structure = this; structure; structure = structure-&gt;storedPrototypeStructure())
+            structure-&gt;startWatchingInternalPropertiesIfNecessary(vm);
+    }
</ins><span class="cx"> 
</span><span class="cx">     PassRefPtr&lt;StructureShape&gt; toStructureShape();
</span><span class="cx">     
</span><span class="lines">@@ -407,11 +424,11 @@
</span><span class="cx">     DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
</span><span class="cx">     DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5);
</span><span class="cx">     DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
</span><del>-    DEFINE_BITFIELD(unsigned, specificFunctionThrashCount, SpecificFunctionThrashCount, 2, 20);
</del><span class="cx">     DEFINE_BITFIELD(bool, preventExtensions, PreventExtensions, 1, 22);
</span><span class="cx">     DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 23);
</span><span class="cx">     DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 24);
</span><span class="cx">     DEFINE_BITFIELD(bool, hasRareData, HasRareData, 1, 25);
</span><ins>+    DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 26);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="lines">@@ -422,7 +439,7 @@
</span><span class="cx"> 
</span><span class="cx">     static Structure* create(VM&amp;, const Structure*);
</span><span class="cx">     
</span><del>-    static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&amp;);
</del><ins>+    static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, PropertyOffset&amp;);
</ins><span class="cx"> 
</span><span class="cx">     // This will return the structure that has a usable property table, that property table,
</span><span class="cx">     // and the list of structures that we visited before we got to it. If it returns a
</span><span class="lines">@@ -432,19 +449,16 @@
</span><span class="cx">     
</span><span class="cx">     static Structure* toDictionaryTransition(VM&amp;, Structure*, DictionaryKind);
</span><span class="cx"> 
</span><del>-    PropertyOffset putSpecificValue(VM&amp;, PropertyName, unsigned attributes, JSCell* specificValue);
</del><ins>+    PropertyOffset add(VM&amp;, PropertyName, unsigned attributes);
</ins><span class="cx">     PropertyOffset remove(PropertyName);
</span><span class="cx"> 
</span><span class="cx">     void createPropertyMap(const GCSafeConcurrentJITLocker&amp;, VM&amp;, unsigned keyCount = 0);
</span><span class="cx">     void checkConsistency();
</span><span class="cx"> 
</span><del>-    bool despecifyFunction(VM&amp;, PropertyName);
-    void despecifyAllFunctions(VM&amp;);
-
</del><span class="cx">     WriteBarrier&lt;PropertyTable&gt;&amp; propertyTable();
</span><del>-    PropertyTable* takePropertyTableOrCloneIfPinned(VM&amp;, Structure* owner);
-    PropertyTable* copyPropertyTable(VM&amp;, Structure* owner);
-    PropertyTable* copyPropertyTableForPinning(VM&amp;, Structure* owner);
</del><ins>+    PropertyTable* takePropertyTableOrCloneIfPinned(VM&amp;);
+    PropertyTable* copyPropertyTable(VM&amp;);
+    PropertyTable* copyPropertyTableForPinning(VM&amp;);
</ins><span class="cx">     JS_EXPORT_PRIVATE void materializePropertyMap(VM&amp;);
</span><span class="cx">     void materializePropertyMapIfNecessary(VM&amp; vm, DeferGC&amp;)
</span><span class="cx">     {
</span><span class="lines">@@ -504,12 +518,12 @@
</span><span class="cx">     bool checkOffsetConsistency() const;
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE void allocateRareData(VM&amp;);
</span><ins>+    
+    void startWatchingInternalProperties(VM&amp;);
</ins><span class="cx"> 
</span><span class="cx">     static const int s_maxTransitionLength = 64;
</span><span class="cx">     static const int s_maxTransitionLengthForNonEvalPutById = 512;
</span><span class="cx"> 
</span><del>-    static const unsigned maxSpecificFunctionThrashCount = 3;
-    
</del><span class="cx">     // These need to be properly aligned at the beginning of the 'Structure'
</span><span class="cx">     // part of the object.
</span><span class="cx">     StructureIDBlob m_blob;
</span><span class="lines">@@ -522,7 +536,6 @@
</span><span class="cx">     WriteBarrier&lt;JSCell&gt; m_previousOrRareData;
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;StringImpl&gt; m_nameInPrevious;
</span><del>-    WriteBarrier&lt;JSCell&gt; m_specificValueInPrevious;
</del><span class="cx"> 
</span><span class="cx">     const ClassInfo* m_classInfo;
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeStructureInlinesh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/StructureInlines.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/StructureInlines.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/StructureInlines.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -102,9 +102,7 @@
</span><span class="cx"> inline PropertyOffset Structure::getConcurrently(VM&amp; vm, StringImpl* uid)
</span><span class="cx"> {
</span><span class="cx">     unsigned attributesIgnored;
</span><del>-    JSCell* specificValueIgnored;
-    return getConcurrently(
-        vm, uid, attributesIgnored, specificValueIgnored);
</del><ins>+    return getConcurrently(vm, uid, attributesIgnored);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool Structure::hasIndexingHeader(const JSCell* cell) const
</span><span class="lines">@@ -223,6 +221,31 @@
</span><span class="cx">     return m_propertyTableUnsafe;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void Structure::didReplaceProperty(PropertyOffset offset)
+{
+    if (LIKELY(!hasRareData()))
+        return;
+    StructureRareData::PropertyWatchpointMap* map = rareData()-&gt;m_replacementWatchpointSets.get();
+    if (LIKELY(!map))
+        return;
+    WatchpointSet* set = map-&gt;get(offset);
+    if (LIKELY(!set))
+        return;
+    set-&gt;fireAll(&quot;Property did get replaced&quot;);
+}
+
+inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset)
+{
+    ConcurrentJITLocker locker(m_lock);
+    if (!hasRareData())
+        return nullptr;
+    WTF::loadLoadFence();
+    StructureRareData::PropertyWatchpointMap* map = rareData()-&gt;m_replacementWatchpointSets.get();
+    if (!map)
+        return nullptr;
+    return map-&gt;get(offset);
+}
+
</ins><span class="cx"> ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
</span><span class="cx"> {
</span><span class="cx">     PropertyTable* propertyTable = m_propertyTableUnsafe.get();
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeStructureRareDatacpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.cpp (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.cpp        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.cpp        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -46,6 +46,11 @@
</span><span class="cx">     return rareData;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void StructureRareData::destroy(JSCell* cell)
+{
+    static_cast&lt;StructureRareData*&gt;(cell)-&gt;StructureRareData::~StructureRareData();
+}
+
</ins><span class="cx"> StructureRareData::StructureRareData(VM&amp; vm, Structure* previous)
</span><span class="cx">     : JSCell(vm, vm.structureRareDataStructure.get())
</span><span class="cx"> {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeStructureRareDatah"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.h (170854 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.h        2014-07-07 20:28:13 UTC (rev 170854)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/StructureRareData.h        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;ClassInfo.h&quot;
</span><span class="cx"> #include &quot;JSCell.h&quot;
</span><span class="cx"> #include &quot;JSTypeInfo.h&quot;
</span><ins>+#include &quot;PropertyOffset.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -40,6 +41,10 @@
</span><span class="cx"> public:
</span><span class="cx">     static StructureRareData* create(VM&amp;, Structure*);
</span><span class="cx"> 
</span><ins>+    static const bool needsDestruction = true;
+    static const bool hasImmortalStructure = true;
+    static void destroy(JSCell*);
+
</ins><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><span class="cx"> 
</span><span class="cx">     static Structure* createStructure(VM&amp;, JSGlobalObject*, JSValue prototype);
</span><span class="lines">@@ -53,10 +58,12 @@
</span><span class="cx"> 
</span><span class="cx">     JSPropertyNameIterator* enumerationCache();
</span><span class="cx">     void setEnumerationCache(VM&amp;, const Structure* owner, JSPropertyNameIterator* value);
</span><del>-
</del><ins>+    
</ins><span class="cx">     DECLARE_EXPORT_INFO;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    friend class Structure;
+    
</ins><span class="cx">     StructureRareData(VM&amp;, Structure*);
</span><span class="cx"> 
</span><span class="cx">     static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags;
</span><span class="lines">@@ -64,6 +71,9 @@
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_previous;
</span><span class="cx">     WriteBarrier&lt;JSString&gt; m_objectToStringValue;
</span><span class="cx">     WriteBarrier&lt;JSPropertyNameIterator&gt; m_enumerationCache;
</span><ins>+    
+    typedef HashMap&lt;PropertyOffset, RefPtr&lt;WatchpointSet&gt;, WTF::IntHash&lt;PropertyOffset&gt;, WTF::UnsignedWithZeroKeyHashTraits&lt;PropertyOffset&gt;&gt; PropertyWatchpointMap;
+    std::unique_ptr&lt;PropertyWatchpointMap&gt; m_replacementWatchpointSets;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressinferconstantglobalpropertyjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-global-property.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-global-property.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-global-property.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+function foo(p) {
+    if (p)
+        Math = {sin: function() { return 42; }, PI: 43, abs: Math.abs};
+}
+
+noInline(foo);
+
+(function() {
+    var n = 100000;
+    var m = 100;
+    var result = 0;
+    for (var i = 0; i &lt; n; ++i) {
+        foo(i == n - m);
+        result += Math.sin(Math.PI);
+    }
+    if (Math.abs(result - m * 42) &gt; 1e-8)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressinferconstantpropertyjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-property.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-property.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/infer-constant-property.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+var o = {f:{f:{f:{f:{f:{f:{f:42}}}}}}};
+
+function foo(p) {
+    if (p)
+        o.f.f.f.f.f.f = {f:53};
+}
+
+noInline(foo);
+
+(function() {
+    var n = 100000;
+    var m = 100;
+    var result = 0;
+    
+    for (var i = 0; i &lt; n; ++i) {
+        foo(i == n - m);
+        result += o.f.f.f.f.f.f.f;
+    }
+    
+    if (result != (n - m) * 42 + m * 53)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressjitcachepolyreplacethencachegetandfoldtheninvalidatejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+var o = {f:42};
+
+function foo(p, o, v) {
+    if (p)
+        o.f = v;
+}
+
+function bar() {
+    return o.f;
+}
+
+noInline(foo);
+noInline(bar);
+
+for (var i = 0; i &lt; 10; ++i)
+    foo(false);
+
+for (var i = 0; i &lt; 10; ++i)
+    foo(true, {}, 42);
+
+for (var i = 0; i &lt; 10; ++i)
+    foo(true, o, 42);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var result = bar();
+    if (result != 42)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+foo(true, o, 53);
+var result = bar();
+if (result != 53)
+    throw &quot;Error: bad result at end: &quot; + result;
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressjitcachereplacethencachegetandfoldtheninvalidatejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+var o = {f:42};
+
+function foo(p, v) {
+    if (p)
+        o.f = v;
+}
+
+function bar() {
+    return o.f;
+}
+
+noInline(foo);
+noInline(bar);
+
+for (var i = 0; i &lt; 10; ++i)
+    foo(false);
+
+for (var i = 0; i &lt; 10; ++i)
+    foo(true, 42);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var result = bar();
+    if (result != 42)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+foo(true, 53);
+var result = bar();
+if (result != 53)
+    throw &quot;Error: bad result at end: &quot; + result;
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressjitputtoscopeglobalcachewatchpointinvalidatejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+function foo(p, v) {
+    if (p)
+        global = v;
+}
+
+function bar() {
+    return global;
+}
+
+noInline(foo);
+noInline(bar);
+
+for (var i = 0; i &lt; 10; ++i)
+    foo(false);
+
+var value = 42;
+foo(true, value);
+var n = 100000;
+var m = 100;
+for (var i = 0; i &lt; n; ++i) {
+    if (i == n - m)
+        foo(true, value = 53);
+    var result = bar();
+    if (result != value)
+        throw &quot;Error: on iteration &quot; + i + &quot; got: &quot; + result;
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressllintcachereplacethencachegetandfoldtheninvalidatejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+var o = {f:42};
+
+function foo(v) {
+    o.f = v;
+}
+
+function bar() {
+    return o.f;
+}
+
+noInline(foo);
+noInline(bar);
+
+foo(42);
+foo(42);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var result = bar();
+    if (result != 42)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+foo(53);
+var result = bar();
+if (result != 53)
+    throw &quot;Error: bad result at end: &quot; + result;
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressllintputtoscopeglobalcachewatchpointinvalidatejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+function foo(v) {
+    global = v;
+}
+
+function bar() {
+    return global;
+}
+
+noInline(foo);
+noInline(bar);
+
+var value = 42;
+foo(value);
+var n = 100000;
+var m = 100;
+for (var i = 0; i &lt; n; ++i) {
+    if (i == n - m)
+        foo(value = 53);
+    var result = bar();
+    if (result != value)
+        throw &quot;Error: on iteration &quot; + i + &quot; got: &quot; + result;
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressrepeatputtoscopeglobalwithsamevaluewatchpointinvalidatejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js (0 => 170855)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js        2014-07-07 20:39:36 UTC (rev 170855)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+function foo(v) {
+    global = v;
+}
+
+function bar() {
+    return global;
+}
+
+noInline(foo);
+noInline(bar);
+
+var value = 42;
+for (var i = 0; i &lt; 10; ++i)
+    foo(value);
+var n = 100000;
+var m = 100;
+for (var i = 0; i &lt; n; ++i) {
+    if (i == n - m)
+        foo(value = 53);
+    var result = bar();
+    if (result != value)
+        throw &quot;Error: on iteration &quot; + i + &quot; got: &quot; + result;
+}
</ins></span></pre>
</div>
</div>

</body>
</html>