Title: [208117] trunk
Revision
208117
Author
[email protected]
Date
2016-10-29 18:38:22 -0700 (Sat, 29 Oct 2016)

Log Message

We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL
https://bugs.webkit.org/show_bug.cgi?id=163305

Reviewed by Keith Miller.

JSTests:

* microbenchmarks/pure-get-by-id-cse-2.js: Added.
(foo):
* microbenchmarks/pure-get-by-id-cse.js: Added.
(foo):
* stress/pure-get-by-id-cse-correctness.js: Added.
(assert):
(foo):
* stress/pure-get-by-id-on-non-object.js: Added.
(assert):
(foo):

Source/_javascript_Core:

This creates a new GetById node in the DFG called PureGetById. We emit a
PureGetById when we profile that a get_by_id in the baseline never does
side effects. PureGetById speculates on the fact that it won't do side
effects. If it realizes that it must perform side effects, it will perform
the side effect, but also invalidate the CodeBlock that compiled it,
which will cause us to exit once we return back to the compiled code.
This allows us to have stricter clobberize rules for PureGetById which
model how getOwnPropertySlot(VMInquiry) behaves. This means that PureGetByIds
can be CSEd with each other, and that other things are more likely to
be CSEd around a PureGetById. To profile if a get_by_id does side
effects, I've added an extra bit into StructureStubInfo that we write
to when performing a get_by_id slow path call. If we notice that we
never do effects, inside the ByteCodeParser, we will emit a PureGetById
instead of a GetById.

To justify the performance benefit of this patch, I ran the suite of
benchmarks with useAccessInlining=false. This meant that we don't compile
any (Multi)GetByOffset/(Multi)PutByOffset. This was just to try to see if
this patch is worth anything at all in a world where we emit many
PureGetByIds. Running the benchmarks under this mode showed a 3.5% octane
improvement and a 15% kraken improvement. However, when running benchmarks
with useAccessInlining=true (the default JSC state), this patch is neutral.
I think the main reason for this is that the DFG is good at knowing when to
emit (Multi)GetByOffset, and most benchmarks that would benefit from
PureGetById are already emitting (Multi)GetByOffset. However, PureGetById can be
profitable when we encounter code that is too polymorphic for (Multi)GetByOffset.
It's reasonable to expect that JS code in the wild will fall into this use
case even though it might not be represented in some of the major JS benchmarks.
I wrote some microbenchmarks to demonstrate the benefits of PureGetById CSE,
and they were 30% (eliminating a few PureGetById from an add _expression_)
to 10x faster (eliminating a PureGetById in a loop).

* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::StructureStubInfo):
(JSC::StructureStubInfo::reset):
* bytecode/StructureStubInfo.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::canBecomeGetArrayLength):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToGetByOffset):
(JSC::DFG::Node::convertToMultiGetByOffset):
(JSC::DFG::Node::hasIdentifier):
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileTryGetById):
(JSC::DFG::SpeculativeJIT::compilePureGetById):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetById):
(JSC::FTL::DFG::LowerDFGToB3::getById):
* jit/JITOperations.cpp:
(JSC::pureGetByIdCommon):
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_try_get_by_id):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_try_get_by_id):
* jit/Repatch.cpp:
(JSC::appropriateOptimizingGetByIdFunction):
(JSC::appropriateGenericGetByIdFunction):
(JSC::tryCacheGetByID):
* jit/Repatch.h:
* profiler/ProfilerJettisonReason.cpp:
(WTF::printInternal):
* profiler/ProfilerJettisonReason.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (208116 => 208117)


--- trunk/JSTests/ChangeLog	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/JSTests/ChangeLog	2016-10-30 01:38:22 UTC (rev 208117)
@@ -1,3 +1,21 @@
+2016-10-29  Saam Barati  <[email protected]>
+
+        We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL
+        https://bugs.webkit.org/show_bug.cgi?id=163305
+
+        Reviewed by Keith Miller.
+
+        * microbenchmarks/pure-get-by-id-cse-2.js: Added.
+        (foo):
+        * microbenchmarks/pure-get-by-id-cse.js: Added.
+        (foo):
+        * stress/pure-get-by-id-cse-correctness.js: Added.
+        (assert):
+        (foo):
+        * stress/pure-get-by-id-on-non-object.js: Added.
+        (assert):
+        (foo):
+
 2016-10-28  Csaba Osztrogonác  <[email protected]>
 
         Skip JSTests/microbenchmarks/dense-set.js on memory limited devices

Added: trunk/JSTests/microbenchmarks/pure-get-by-id-cse-2.js (0 => 208117)


--- trunk/JSTests/microbenchmarks/pure-get-by-id-cse-2.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/pure-get-by-id-cse-2.js	2016-10-30 01:38:22 UTC (rev 208117)
@@ -0,0 +1,30 @@
+function foo(o, c) {
+    if (o.f) {
+        let sum = 0;
+        for (let i = 0; i < c; i++)
+            sum += o.f;
+        return sum;
+    }
+}
+noInline(foo);
+
+let start = Date.now();
+let objects = [];
+const objectCount = 20;
+for (let i = 0; i < objectCount; i++) {
+    let obj = {};
+    for (let j = 0; j < i * 2; j++) {
+        obj["j" + j] = j;
+    }
+    obj.f = 20;
+    objects.push(obj);
+}
+
+for (let i = 0; i < 1000000; i++) {
+    let obj = objects[i % objects.length];
+    foo(obj, 150);
+}
+
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);

Added: trunk/JSTests/microbenchmarks/pure-get-by-id-cse.js (0 => 208117)


--- trunk/JSTests/microbenchmarks/pure-get-by-id-cse.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/pure-get-by-id-cse.js	2016-10-30 01:38:22 UTC (rev 208117)
@@ -0,0 +1,26 @@
+function foo(o) {
+    if (o.f)
+        return o.f + o.f + o.f + o.f; 
+}
+noInline(foo);
+
+let start = Date.now();
+let objects = [];
+const objectCount = 20;
+for (let i = 0; i < objectCount; i++) {
+    let obj = {};
+    for (let j = 0; j < i * 2; j++) {
+        obj["j" + j] = j;
+    }
+    obj.f = 20;
+    objects.push(obj);
+}
+
+for (let i = 0; i < 10000000; i++) {
+    let obj = objects[i % objects.length];
+    foo(obj);
+}
+
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);

Added: trunk/JSTests/stress/pure-get-by-id-cse-correctness.js (0 => 208117)


--- trunk/JSTests/stress/pure-get-by-id-cse-correctness.js	                        (rev 0)
+++ trunk/JSTests/stress/pure-get-by-id-cse-correctness.js	2016-10-30 01:38:22 UTC (rev 208117)
@@ -0,0 +1,39 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion")
+}
+noInline(assert);
+
+function foo(o1, o2) {
+    let a = o1.f1;
+    let b = o2.f2;
+    return a + o1.f1 + b;
+}
+noInline(foo);
+
+let objs = [];
+const count = 80;
+for (let i = 0; i < count; i++) {
+    let o = {};
+    for (let j = 0; j < i; ++j) {
+        o[j + "J"] = j;
+    }
+    o.f1 = 20;
+    o.f2 = 40;
+    objs.push(o);
+}
+
+for (let i = 0; i < 1000; i++) {
+    let o1 = objs[i % objs.length];
+    let o2 = objs[(i + 1) % objs.length];
+    assert(foo(o1, o2) === 80);
+}
+
+let o = objs[count - 1];
+let numCalls = 0;
+Object.defineProperty(o, "f1", {
+    get() { ++numCalls; return 25; }
+});
+
+assert(foo(o, objs[count - 2]) === 90);
+assert(numCalls === 2);

Added: trunk/JSTests/stress/pure-get-by-id-on-non-object.js (0 => 208117)


--- trunk/JSTests/stress/pure-get-by-id-on-non-object.js	                        (rev 0)
+++ trunk/JSTests/stress/pure-get-by-id-on-non-object.js	2016-10-30 01:38:22 UTC (rev 208117)
@@ -0,0 +1,32 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.")
+}
+
+function foo(o) {
+    assert(o.length === o.length);
+    return o.length;
+}
+noInline(foo);
+
+let items = [];
+const numItems = 30;
+for (let i = 0; i < numItems; i++) {
+    let o = {};
+    for (let j = 0; j < i; j++) {
+        o[j + "j"] = j;
+    }
+    o.length = 2;
+    items.push(o);
+} 
+
+items.push("st");
+
+for (let i = 0; i < 10000; i++)
+    assert(foo(items[i % items.length]) === 2);
+
+Number.prototype.length = 2;
+items.push(42);
+
+for (let i = 0; i < 100000; i++)
+    assert(foo(items[i % items.length]) === 2);

Modified: trunk/Source/_javascript_Core/ChangeLog (208116 => 208117)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-30 01:38:22 UTC (rev 208117)
@@ -1,3 +1,102 @@
+2016-10-29  Saam Barati  <[email protected]>
+
+        We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL
+        https://bugs.webkit.org/show_bug.cgi?id=163305
+
+        Reviewed by Keith Miller.
+
+        This creates a new GetById node in the DFG called PureGetById. We emit a
+        PureGetById when we profile that a get_by_id in the baseline never does
+        side effects. PureGetById speculates on the fact that it won't do side
+        effects. If it realizes that it must perform side effects, it will perform
+        the side effect, but also invalidate the CodeBlock that compiled it,
+        which will cause us to exit once we return back to the compiled code.
+        This allows us to have stricter clobberize rules for PureGetById which
+        model how getOwnPropertySlot(VMInquiry) behaves. This means that PureGetByIds
+        can be CSEd with each other, and that other things are more likely to
+        be CSEd around a PureGetById. To profile if a get_by_id does side
+        effects, I've added an extra bit into StructureStubInfo that we write
+        to when performing a get_by_id slow path call. If we notice that we
+        never do effects, inside the ByteCodeParser, we will emit a PureGetById
+        instead of a GetById.
+
+        To justify the performance benefit of this patch, I ran the suite of
+        benchmarks with useAccessInlining=false. This meant that we don't compile
+        any (Multi)GetByOffset/(Multi)PutByOffset. This was just to try to see if
+        this patch is worth anything at all in a world where we emit many
+        PureGetByIds. Running the benchmarks under this mode showed a 3.5% octane
+        improvement and a 15% kraken improvement. However, when running benchmarks
+        with useAccessInlining=true (the default JSC state), this patch is neutral.
+        I think the main reason for this is that the DFG is good at knowing when to
+        emit (Multi)GetByOffset, and most benchmarks that would benefit from
+        PureGetById are already emitting (Multi)GetByOffset. However, PureGetById can be
+        profitable when we encounter code that is too polymorphic for (Multi)GetByOffset.
+        It's reasonable to expect that JS code in the wild will fall into this use
+        case even though it might not be represented in some of the major JS benchmarks.
+        I wrote some microbenchmarks to demonstrate the benefits of PureGetById CSE,
+        and they were 30% (eliminating a few PureGetById from an add _expression_)
+        to 10x faster (eliminating a PureGetById in a loop).
+
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::StructureStubInfo):
+        (JSC::StructureStubInfo::reset):
+        * bytecode/StructureStubInfo.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::canBecomeGetArrayLength):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToGetByOffset):
+        (JSC::DFG::Node::convertToMultiGetByOffset):
+        (JSC::DFG::Node::hasIdentifier):
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileTryGetById):
+        (JSC::DFG::SpeculativeJIT::compilePureGetById):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetById):
+        (JSC::FTL::DFG::LowerDFGToB3::getById):
+        * jit/JITOperations.cpp:
+        (JSC::pureGetByIdCommon):
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_try_get_by_id):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_try_get_by_id):
+        * jit/Repatch.cpp:
+        (JSC::appropriateOptimizingGetByIdFunction):
+        (JSC::appropriateGenericGetByIdFunction):
+        (JSC::tryCacheGetByID):
+        * jit/Repatch.h:
+        * profiler/ProfilerJettisonReason.cpp:
+        (WTF::printInternal):
+        * profiler/ProfilerJettisonReason.h:
+
 2016-10-28  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Breakpoints not working in scripts with unicode characters

Modified: trunk/Source/_javascript_Core/bytecode/StructureStubInfo.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/bytecode/StructureStubInfo.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/bytecode/StructureStubInfo.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -48,6 +48,7 @@
     , resetByGC(false)
     , tookSlowPath(false)
     , everConsidered(false)
+    , didSideEffects(false)
 {
 }
 
@@ -216,7 +217,10 @@
     }
 
     switch (accessType) {
-    case AccessType::GetPure:
+    case AccessType::TryGet:
+        resetGetByID(codeBlock, *this, GetByIDKind::Try);
+        break;
+    case AccessType::PureGet:
         resetGetByID(codeBlock, *this, GetByIDKind::Pure);
         break;
     case AccessType::Get:

Modified: trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h (208116 => 208117)


--- trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -46,7 +46,8 @@
 
 enum class AccessType : int8_t {
     Get,
-    GetPure,
+    TryGet,
+    PureGet,
     Put,
     In
 };
@@ -205,6 +206,7 @@
     bool resetByGC : 1;
     bool tookSlowPath : 1;
     bool everConsidered : 1;
+    bool didSideEffects : 1;
 };
 
 inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStubInfo)

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -2119,6 +2119,7 @@
         forNode(node).makeHeapTop();
         break;
 
+    case PureGetById:
     case GetById:
     case GetByIdFlush: {
         if (!node->prediction()) {
@@ -2150,7 +2151,10 @@
             }
         }
 
-        clobberWorld(node->origin.semantic, clobberLimit);
+        if (node->op() == PureGetById)
+            clobberStructures(clobberLimit);
+        else
+            clobberWorld(node->origin.semantic, clobberLimit);
         forNode(node).makeHeapTop();
         break;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -152,10 +152,11 @@
 
 static bool canBecomeGetArrayLength(Graph& graph, Node* node)
 {
-    if (node->op() != GetById)
-        return false;
-    auto uid = graph.identifiers()[node->identifierNumber()];
-    return uid == graph.m_vm.propertyNames->length.impl();
+    if (node->op() == GetById || node->op() == PureGetById) {
+        auto uid = graph.identifiers()[node->identifierNumber()];
+        return uid == graph.m_vm.propertyNames->length.impl();
+    }
+    return false;
 }
 
 ArrayMode ArrayMode::refine(

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -3307,10 +3307,19 @@
     }
     
     NodeType getById;
-    if (type == AccessType::Get)
+    switch (type) {
+    case AccessType::Get:
         getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById;
-    else
+        break;
+    case AccessType::TryGet:
         getById = TryGetById;
+        break;
+    case AccessType::PureGet:
+        getById = PureGetById;
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 
     // Special path for custom accessors since custom's offset does not have any meanings.
     // So, this is completely different from Simple one. But we have a chance to optimize it when we use DOMJIT.
@@ -4198,7 +4207,8 @@
 
             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
             Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
-            bool compiledAsGetById = false;
+            bool compileAsGetById = false;
+            bool compileAsPureGetById = false;
             GetByIdStatus getByIdStatus;
             unsigned identifierNumber = 0;
             {
@@ -4207,7 +4217,8 @@
                 // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null.
                 // At that time, there is no information.
                 if (byValInfo && byValInfo->stubInfo && !byValInfo->tookSlowPath && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) {
-                    compiledAsGetById = true;
+                    compileAsGetById = true;
+                    compileAsPureGetById = !byValInfo->stubInfo->didSideEffects;
                     identifierNumber = m_graph.identifiers().ensure(byValInfo->cachedId.impl());
                     UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber];
 
@@ -4225,9 +4236,10 @@
                 }
             }
 
-            if (compiledAsGetById)
-                handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, AccessType::Get, OPCODE_LENGTH(op_get_by_val));
-            else {
+            if (compileAsGetById) {
+                AccessType type = compileAsPureGetById ? AccessType::PureGet : AccessType::Get;
+                handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, type, OPCODE_LENGTH(op_get_by_val));
+            } else {
                 ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
                 Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property);
                 m_exitOK = false; // GetByVal must be treated as if it clobbers exit state, since FixupPhase may make it generic.
@@ -4363,7 +4375,18 @@
                 m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock,
                 m_inlineStackTop->m_stubInfos, m_dfgStubInfos,
                 currentCodeOrigin(), uid);
-            AccessType type = op_try_get_by_id == opcodeID ? AccessType::GetPure : AccessType::Get;
+            AccessType type;
+            if (opcodeID == op_try_get_by_id) 
+                type = AccessType::TryGet;
+            else {
+                ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+                unsigned bytecodeIndex = currentCodeOrigin().bytecodeIndex;
+                StructureStubInfo* info = m_inlineStackTop->m_stubInfos.get(CodeOrigin(bytecodeIndex));
+                if (info && info->everConsidered && !info->didSideEffects)
+                    type = AccessType::PureGet;
+                else
+                    type = AccessType::Get;
+            }
 
             unsigned opcodeLength = opcodeID == op_try_get_by_id ? OPCODE_LENGTH(op_try_get_by_id) : OPCODE_LENGTH(op_get_by_id);
 

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -495,6 +495,35 @@
         def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
         return;
         
+    case PureGetById: {
+        // We model what is allowed inside a getOwnPropertySlot(VMInquiry) here.
+        // Some getOwnPropertySlot implementations will lazily inject properties, which
+        // may change the object's structure.
+
+        read(JSCell_structureID);
+        read(JSCell_typeInfoFlags);
+        read(JSCell_typeInfoType);
+        read(JSCell_indexingType);
+        read(JSObject_butterfly);
+        read(MiscFields);
+
+        AbstractHeap propertyNameHeap(NamedProperties, node->identifierNumber());
+        read(propertyNameHeap);
+
+        write(JSCell_structureID);
+        write(JSCell_typeInfoFlags);
+
+        write(Watchpoint_fire);
+        write(MiscFields);
+
+        // This can happen if lazily adding fields to an object happens in getOwnPropertySlot
+        // and we need to allocate out of line storage.
+        write(JSObject_butterfly);
+
+        def(HeapLocation(NamedPropertyLoc, propertyNameHeap, node->child1()), LazyNode(node));
+        return;
+    }
+
     case GetById:
     case GetByIdFlush:
     case GetByIdWithThis:

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -448,6 +448,7 @@
                 break;
             }
         
+            case PureGetById:
             case GetById:
             case GetByIdFlush: {
                 Edge childEdge = node->child1();
@@ -459,6 +460,9 @@
                 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
                 alreadyHandled = true; // Don't allow the default constant folder to do things to this.
 
+                if (!Options::useAccessInlining())
+                    break;
+
                 if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()
                     || (node->child1().useKind() == UntypedUse || (baseValue.m_type & ~SpecCell)))
                     break;
@@ -514,6 +518,9 @@
                 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
                 alreadyHandled = true; // Don't allow the default constant folder to do things to this.
 
+                if (!Options::useAccessInlining())
+                    break;
+
                 if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered())
                     break;
                 

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -264,6 +264,7 @@
     case ResolveScope:
         return false;
 
+    case PureGetById: // We are modeling getOwnPropertySlot here, which may GC because it is allowed to allocate things.
     case CreateActivation:
     case CreateDirectArguments:
     case CreateScopedArguments:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -1167,6 +1167,7 @@
             break;
         }
 
+        case PureGetById:
         case GetById:
         case GetByIdFlush: {
             // FIXME: This should be done in the ByteCodeParser based on reading the

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -532,7 +532,7 @@
     
     void convertToGetByOffset(StorageAccessData& data, Edge storage, Edge base)
     {
-        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset);
+        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById || m_op == MultiGetByOffset);
         m_opInfo = &data;
         children.setChild1(storage);
         children.setChild2(base);
@@ -542,7 +542,7 @@
     
     void convertToMultiGetByOffset(MultiGetByOffsetData* data)
     {
-        ASSERT(m_op == GetById || m_op == GetByIdFlush);
+        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById);
         m_opInfo = data;
         child1().setUseKind(CellUse);
         m_op = MultiGetByOffset;
@@ -918,6 +918,7 @@
         switch (op()) {
         case TryGetById:
         case GetById:
+        case PureGetById:
         case GetByIdFlush:
         case GetByIdWithThis:
         case PutById:
@@ -1428,6 +1429,7 @@
         case ArithCeil:
         case ArithTrunc:
         case GetDirectPname:
+        case PureGetById:
         case GetById:
         case GetByIdFlush:
         case GetByIdWithThis:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -185,6 +185,7 @@
     macro(PutByVal, NodeMustGenerate | NodeHasVarArgs) \
     macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs) \
     macro(TryGetById, NodeResultJS) \
+    macro(PureGetById, NodeResultJS | NodeMustGenerate) \
     macro(GetById, NodeResultJS | NodeMustGenerate) \
     macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \
     macro(GetByIdWithThis, NodeResultJS | NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -682,6 +682,7 @@
         case RegExpTest:
         case StringReplace:
         case StringReplaceRegExp:
+        case PureGetById:
         case GetById:
         case GetByIdFlush:
         case GetByIdWithThis:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -199,6 +199,7 @@
     case TryGetById:
     case DeleteById:
     case DeleteByVal:
+    case PureGetById:
     case GetById:
     case GetByIdWithThis:
     case GetByValWithThis:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -1003,7 +1003,7 @@
 
         base.use();
 
-        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::GetPure);
+        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::TryGet);
 
         jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
         break;
@@ -1020,7 +1020,7 @@
 
         JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
 
-        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::GetPure);
+        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::TryGet);
 
         jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
         break;
@@ -1032,6 +1032,42 @@
     } 
 }
 
+void SpeculativeJIT::compilePureGetById(Node* node)
+{
+    ASSERT(node->op() == PureGetById);
+
+    switch (node->child1().useKind()) {
+    case CellUse: {
+        SpeculateCellOperand base(this, node->child1());
+        JSValueRegsTemporary result(this, Reuse, base);
+
+        JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
+        JSValueRegs resultRegs = result.regs();
+
+        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::PureGet);
+
+        jsValueResult(resultRegs, node);
+        break;
+    }
+    case UntypedUse: {
+        JSValueOperand base(this, node->child1());
+        JSValueRegsTemporary result(this, Reuse, base);
+
+        JSValueRegs baseRegs = base.jsValueRegs();
+        JSValueRegs resultRegs = result.regs();
+    
+        JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
+    
+        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::PureGet);
+    
+        jsValueResult(resultRegs, node);
+        break;
+    }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
 void SpeculativeJIT::compileIn(Node* node)
 {
     SpeculateCellOperand base(this, node->child2());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -721,6 +721,7 @@
     void compileDeleteById(Node*);
     void compileDeleteByVal(Node*);
     void compileTryGetById(Node*);
+    void compilePureGetById(Node*);
     void compileIn(Node*);
     
     void nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -210,6 +210,8 @@
     J_JITOperation_ESsiJI getByIdFunction;
     if (type == AccessType::Get)
         getByIdFunction = operationGetByIdOptimize;
+    else if (type == AccessType::PureGet)
+        getByIdFunction = operationPureGetByIdOptimize;
     else
         getByIdFunction = operationTryGetByIdOptimize;
 
@@ -4269,6 +4271,11 @@
         break;
     }
 
+    case PureGetById: {
+        compilePureGetById(node);
+        break;
+    }
+
     case GetByIdWithThis: {
         JSValueOperand base(this, node->child1());
         JSValueRegs baseRegs = base.jsValueRegs();

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -179,8 +179,11 @@
         slowCases.append(slowPathTarget);
     slowCases.append(gen.slowPathJump());
     
+    auto slowPathFunction = type == AccessType::Get ? operationGetByIdOptimize :
+        type == AccessType::PureGet ? operationPureGetByIdOptimize : operationTryGetByIdOptimize;
+
     auto slowPath = slowPathCall(
-        slowCases, this, type == AccessType::Get ? operationGetByIdOptimize : operationTryGetByIdOptimize,
+        slowCases, this, slowPathFunction,
         spillMode, ExceptionCheckRequirement::CheckNeeded,
         resultGPR, gen.stubInfo(), baseGPR, identifierUID(identifierNumber));
     
@@ -4235,6 +4238,11 @@
         break;
     }
 
+    case PureGetById: {
+        compilePureGetById(node);
+        break;
+    }
+
     case GetByIdFlush: {
         if (!node->prediction()) {
             terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -176,6 +176,7 @@
     case NewArrayWithSize:
     case TryGetById:
     case GetById:
+    case PureGetById:
     case GetByIdFlush:
     case GetByIdWithThis:
     case ToThis:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -623,8 +623,11 @@
             compilePutStructure();
             break;
         case TryGetById:
-            compileGetById(AccessType::GetPure);
+            compileGetById(AccessType::TryGet);
             break;
+        case PureGetById:
+            compileGetById(AccessType::PureGet);
+            break;
         case GetById:
         case GetByIdFlush:
             compileGetById(AccessType::Get);
@@ -2788,7 +2791,7 @@
     
     void compileGetById(AccessType type)
     {
-        ASSERT(type == AccessType::Get || type == AccessType::GetPure);
+        ASSERT(type == AccessType::Get || type == AccessType::TryGet || type == AccessType::PureGet);
         switch (m_node->child1().useKind()) {
         case CellUse: {
             setJSValue(getById(lowCell(m_node->child1()), type));
@@ -2815,6 +2818,8 @@
             J_JITOperation_EJI getByIdFunction;
             if (type == AccessType::Get)
                 getByIdFunction = operationGetByIdGeneric;
+            else if (type == AccessType::PureGet)
+                getByIdFunction = operationPureGetByIdGeneric;
             else
                 getByIdFunction = operationTryGetByIdGeneric;
 
@@ -8838,6 +8843,8 @@
                         J_JITOperation_ESsiJI optimizationFunction;
                         if (type == AccessType::Get)
                             optimizationFunction = operationGetByIdOptimize;
+                        else if (type == AccessType::PureGet)
+                            optimizationFunction = operationPureGetByIdOptimize;
                         else
                             optimizationFunction = operationTryGetByIdOptimize;
 

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -70,6 +70,35 @@
 
 namespace JSC {
 
+ALWAYS_INLINE static EncodedJSValue pureGetByIdCommon(VM& vm, ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid, const std::function<void (const PropertySlot&, const Identifier&)>& function = [] (const PropertySlot&, const Identifier&) { })
+{
+    Identifier ident = Identifier::fromUid(&vm, uid);
+    JSValue baseValue = JSValue::decode(base);
+
+    ASSERT(JITCode::isOptimizingJIT(exec->codeBlock()->jitType()));
+
+    PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
+    return JSValue::encode(baseValue.getPropertySlot(exec, ident, slot, [&] (bool, PropertySlot&) -> JSValue {
+        bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject();
+        if (UNLIKELY(willDoSideEffects)) {
+            {
+                CodeOrigin codeOrigin = exec->codeOrigin();
+                CodeBlock* currentBaseline = baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, exec->codeBlock()->alternative());
+                CodeOrigin originBytecodeIndex = CodeOrigin(codeOrigin.bytecodeIndex); // Since we're searching in the baseline, we just care about bytecode index.
+                ConcurrentJITLocker locker(currentBaseline->m_lock);
+                if (StructureStubInfo* stub = currentBaseline->findStubInfo(originBytecodeIndex))
+                    stub->didSideEffects = true;
+            }
+
+            exec->codeBlock()->jettison(Profiler::JettisonDueToPureGetByIdEffects);
+            return baseValue.get(exec, uid);
+        }
+
+        function(slot, ident);
+        return slot.isValue() ? slot.getValue(exec, ident) : jsUndefined();
+    }));
+}
+
 extern "C" {
 
 #if COMPILER(MSVC)
@@ -165,6 +194,38 @@
     return missingArgCount;
 }
 
+EncodedJSValue JIT_OPERATION operationPureGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    return pureGetByIdCommon(*vm, exec, base, uid);
+}
+
+EncodedJSValue JIT_OPERATION operationPureGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    stubInfo->tookSlowPath = true;
+
+    return pureGetByIdCommon(*vm, exec, base, uid);
+}
+
+EncodedJSValue JIT_OPERATION operationPureGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    return pureGetByIdCommon(*vm, exec, base, uid, 
+        [&] (const PropertySlot& slot, const Identifier& ident) {
+            ASSERT((slot.isValue() || slot.isUnset()) && !slot.isTaintedByOpaqueObject());
+            JSValue baseValue = JSValue::decode(base);
+            if (stubInfo->considerCaching(baseValue.structureOrNull()))
+                repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Pure);
+        });
+}
+
 EncodedJSValue JIT_OPERATION operationTryGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
 {
     VM* vm = &exec->vm();
@@ -179,7 +240,6 @@
     return JSValue::encode(slot.getPureResult());
 }
 
-
 EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
 {
     VM* vm = &exec->vm();
@@ -207,7 +267,7 @@
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
     if (stubInfo->considerCaching(baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset()))
-        repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Pure);
+        repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Try);
 
     return JSValue::encode(slot.getPureResult());
 }
@@ -226,7 +286,10 @@
     Identifier ident = Identifier::fromUid(vm, uid);
     
     LOG_IC((ICEvent::OperationGetById, baseValue.classInfoOrNull(), ident));
-    return JSValue::encode(baseValue.get(exec, ident, slot));
+    JSValue result = baseValue.get(exec, ident, slot);
+    bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject();
+    stubInfo->didSideEffects |= willDoSideEffects;
+    return JSValue::encode(result);
 }
 
 EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
@@ -255,6 +318,9 @@
     LOG_IC((ICEvent::OperationGetByIdOptimize, baseValue.classInfoOrNull(), ident));
 
     return JSValue::encode(baseValue.getPropertySlot(exec, ident, [&] (bool found, PropertySlot& slot) -> JSValue {
+        bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject();
+        stubInfo->didSideEffects |= willDoSideEffects;
+
         if (stubInfo->considerCaching(baseValue.structureOrNull()))
             repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Normal);
         return found ? slot.getValue(exec, ident) : jsUndefined();

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (208116 => 208117)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -330,6 +330,9 @@
 EncodedJSValue JIT_OPERATION operationTryGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationTryGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationPureGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationPureGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationPureGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -579,7 +579,7 @@
 
     JITGetByIdGenerator gen(
         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
-        ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0), AccessType::GetPure);
+        ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0), AccessType::TryGet);
     gen.generateFastPath(*this);
     addSlowCase(gen.slowPathJump());
     m_getByIds.append(gen);

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -594,7 +594,7 @@
 
     JITGetByIdGenerator gen(
         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
-        ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), AccessType::GetPure);
+        ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), AccessType::TryGet);
     gen.generateFastPath(*this);
     addSlowCase(gen.slowPathJump());
     m_getByIds.append(gen);

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -134,16 +134,34 @@
 
 inline J_JITOperation_ESsiJI appropriateOptimizingGetByIdFunction(GetByIDKind kind)
 {
-    if (kind == GetByIDKind::Normal)
+    switch (kind) {
+    case GetByIDKind::Normal:
         return operationGetByIdOptimize;
-    return operationTryGetByIdOptimize;
+    case GetByIDKind::Try:
+        return operationTryGetByIdOptimize;
+    case GetByIDKind::Pure:
+        return operationPureGetByIdOptimize;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return operationGetByIdOptimize;
 }
 
 inline J_JITOperation_ESsiJI appropriateGenericGetByIdFunction(GetByIDKind kind)
 {
-    if (kind == GetByIDKind::Normal)
+    switch (kind) {
+    case GetByIDKind::Normal:
         return operationGetById;
-    return operationTryGetById;
+    case GetByIDKind::Try:
+        return operationTryGetById;
+    case GetByIDKind::Pure:
+        return operationPureGetById;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return operationGetById;
 }
 
 static InlineCacheAction tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo, GetByIDKind kind)
@@ -271,6 +289,16 @@
                 type = AccessCase::Load;
             else if (slot.isUnset())
                 type = AccessCase::Miss;
+            else
+                RELEASE_ASSERT_NOT_REACHED();
+
+            newCase = AccessCase::tryGet(vm, codeBlock, type, offset, structure, conditionSet, loadTargetFromProxy, slot.watchpointSet());
+        } else if (kind == GetByIDKind::Try) {
+            AccessCase::AccessType type;
+            if (slot.isCacheableValue())
+                type = AccessCase::Load;
+            else if (slot.isUnset())
+                type = AccessCase::Miss;
             else if (slot.isCacheableGetter())
                 type = AccessCase::GetGetter;
             else

Modified: trunk/Source/_javascript_Core/jit/Repatch.h (208116 => 208117)


--- trunk/Source/_javascript_Core/jit/Repatch.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/jit/Repatch.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -36,6 +36,7 @@
 
 enum class GetByIDKind {
     Normal,
+    Try,
     Pure
 };
 

Modified: trunk/Source/_javascript_Core/profiler/ProfilerJettisonReason.cpp (208116 => 208117)


--- trunk/Source/_javascript_Core/profiler/ProfilerJettisonReason.cpp	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/profiler/ProfilerJettisonReason.cpp	2016-10-30 01:38:22 UTC (rev 208117)
@@ -56,6 +56,9 @@
     case JettisonDueToOSRExit:
         out.print("OSRExit");
         return;
+    case JettisonDueToPureGetByIdEffects:
+        out.print("PureGetByIdEffects");
+        return;
     case JettisonDueToProfiledWatchpoint:
         out.print("ProfiledWatchpoint");
         return;

Modified: trunk/Source/_javascript_Core/profiler/ProfilerJettisonReason.h (208116 => 208117)


--- trunk/Source/_javascript_Core/profiler/ProfilerJettisonReason.h	2016-10-29 22:34:43 UTC (rev 208116)
+++ trunk/Source/_javascript_Core/profiler/ProfilerJettisonReason.h	2016-10-30 01:38:22 UTC (rev 208117)
@@ -35,6 +35,7 @@
     JettisonDueToBaselineLoopReoptimizationTrigger,
     JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail,
     JettisonDueToOSRExit,
+    JettisonDueToPureGetByIdEffects,
     JettisonDueToProfiledWatchpoint,
     JettisonDueToUnprofiledWatchpoint,
     JettisonDueToOldAge
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to