Title: [206136] trunk
Revision
206136
Author
sbar...@apple.com
Date
2016-09-19 18:05:50 -0700 (Mon, 19 Sep 2016)

Log Message

Make HasOwnProperty faster
https://bugs.webkit.org/show_bug.cgi?id=161708

Reviewed by Geoffrey Garen.

JSTests:

* microbenchmarks/has-own-property-name-cache.js: Added.
(foo):
* stress/has-own-property-cache-basics.js: Added.
(assert):
(foo):
* stress/has-own-property-name-cache-string-keys.js: Added.
(assert):
(foo):
* stress/has-own-property-name-cache-symbol-keys.js: Added.
(assert):
(foo):
* stress/has-own-property-name-cache-symbols-and-strings.js: Added.
(assert):
(foo):

Source/_javascript_Core:

This patch adds a cache for HasOwnProperty. The cache holds tuples
of {StructureID, UniquedStringImpl*, boolean} where the boolean indicates
the result of performing hasOwnProperty on an object with StructureID and
UniquedStringImpl*. If the cache contains an item, we can be guaranteed
that it contains the same result as performing hasOwnProperty on an
object O with a given structure and key. To guarantee this, we only add
items into the cache when the Structure of the given item is cacheable.

The caching strategy is simple: when adding new items into the cache,
we will evict any item that was in the location that the new item
is hashed into. We also clear the cache on every GC. This strategy
proves to be successful on speedometer, which sees a cache hit rate
over 90%. This caching strategy is now inlined into the DFG/FTL JITs
by now recognizing hasOwnProperty as an intrinsic with the corresponding
HasOwnProperty node. The goal of the node is to emit inlined code for
the cache lookup to prevent the overhead of the call for the common
case where we get a cache hit.

I'm seeing around a 1% to 1.5% percent improvement on Speedometer on
my machine. Hopefully the perf bots agree with my machine.

This patch also speeds up the microbenchmark I added by 2.5x.

* _javascript_Core.xcodeproj/project.pbxproj:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
* heap/Heap.cpp:
(JSC::Heap::collectImpl):
* jit/JITOperations.h:
* runtime/HasOwnPropertyCache.h: Added.
(JSC::HasOwnPropertyCache::Entry::offsetOfStructureID):
(JSC::HasOwnPropertyCache::Entry::offsetOfImpl):
(JSC::HasOwnPropertyCache::Entry::offsetOfResult):
(JSC::HasOwnPropertyCache::operator delete):
(JSC::HasOwnPropertyCache::create):
(JSC::HasOwnPropertyCache::hash):
(JSC::HasOwnPropertyCache::get):
(JSC::HasOwnPropertyCache::tryAdd):
(JSC::HasOwnPropertyCache::clear):
(JSC::VM::ensureHasOwnPropertyCache):
* runtime/Intrinsic.h:
* runtime/JSObject.h:
* runtime/JSObjectInlines.h:
(JSC::JSObject::hasOwnProperty):
* runtime/ObjectPrototype.cpp:
(JSC::ObjectPrototype::finishCreation):
(JSC::objectProtoFuncHasOwnProperty):
* runtime/Symbol.h:
* runtime/VM.cpp:
* runtime/VM.h:
(JSC::VM::hasOwnPropertyCache):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (206135 => 206136)


--- trunk/JSTests/ChangeLog	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/JSTests/ChangeLog	2016-09-20 01:05:50 UTC (rev 206136)
@@ -1,3 +1,25 @@
+2016-09-19  Saam Barati  <sbar...@apple.com>
+
+        Make HasOwnProperty faster
+        https://bugs.webkit.org/show_bug.cgi?id=161708
+
+        Reviewed by Geoffrey Garen.
+
+        * microbenchmarks/has-own-property-name-cache.js: Added.
+        (foo):
+        * stress/has-own-property-cache-basics.js: Added.
+        (assert):
+        (foo):
+        * stress/has-own-property-name-cache-string-keys.js: Added.
+        (assert):
+        (foo):
+        * stress/has-own-property-name-cache-symbol-keys.js: Added.
+        (assert):
+        (foo):
+        * stress/has-own-property-name-cache-symbols-and-strings.js: Added.
+        (assert):
+        (foo):
+
 2016-09-19  Benjamin Poulain  <bpoul...@apple.com>
 
         [JSC] Make the rounding-related nodes support any type

Added: trunk/JSTests/microbenchmarks/has-own-property-name-cache.js (0 => 206136)


--- trunk/JSTests/microbenchmarks/has-own-property-name-cache.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/has-own-property-name-cache.js	2016-09-20 01:05:50 UTC (rev 206136)
@@ -0,0 +1,45 @@
+let objs = [
+    {
+        __proto__: { 
+            foo: 25
+        },
+        bar: 50,
+        baz: 75,
+        jaz: 80,
+    },
+    {
+        __proto__: { 
+            bar: 25
+        },
+        baz: 75,
+        kaz: 80,
+        bar: 50,
+        jaz: 80,
+    },
+    {
+        __proto__: { 
+            bar: 25,
+            jaz: 50
+        },
+        bar: 50,
+        baz: 75,
+        kaz: 80,
+        jaz: 80,
+        foo: 55
+    }
+];
+
+function foo(o) {
+    for (let p in o)
+        o.hasOwnProperty(p);
+
+}
+noInline(foo);
+
+let start = Date.now();
+for (let i = 0; i < 1000000; ++i) {
+    foo(objs[i % objs.length]);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);

Added: trunk/JSTests/stress/has-own-property-cache-basics.js (0 => 206136)


--- trunk/JSTests/stress/has-own-property-cache-basics.js	                        (rev 0)
+++ trunk/JSTests/stress/has-own-property-cache-basics.js	2016-09-20 01:05:50 UTC (rev 206136)
@@ -0,0 +1,31 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.")
+}
+noInline(assert);
+
+let objs = [
+    {f: 50},
+    {f: 50, g: 70},
+    {g: 50, f: 70},
+    {h: 50, f: 70},
+    {z: 50, f: 70},
+    {k: 50, f: 70},
+];
+
+let s1 = Symbol();
+let s2 = Symbol();
+for (let o of objs)
+    o[s1] = "foo";
+
+function foo(o) {
+    assert(o.hasOwnProperty("f"));
+    assert(!o.hasOwnProperty("ff"));
+    assert(o.hasOwnProperty(s1));
+    assert(!o.hasOwnProperty(s2));
+}
+noInline(foo);
+
+for (let i = 0; i < 40000; ++i) {
+    foo(objs[i % objs.length]);
+}

Added: trunk/JSTests/stress/has-own-property-name-cache-string-keys.js (0 => 206136)


--- trunk/JSTests/stress/has-own-property-name-cache-string-keys.js	                        (rev 0)
+++ trunk/JSTests/stress/has-own-property-name-cache-string-keys.js	2016-09-20 01:05:50 UTC (rev 206136)
@@ -0,0 +1,37 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.");
+}
+noInline(assert);
+
+let objs = [];
+let keyPool = [];
+const numKeys = 800;
+for (let i = 0; i < numKeys; ++i)
+    keyPool.push(i + "foo");
+
+for (let i = 0; i < 10000; i++) {
+    let num = (Math.random() * numKeys) | 0;
+    let o = {};
+    for (let i = 0; i < num; ++i) {
+        o[keyPool[i]] = 25; 
+    }
+    objs.push(o);
+}
+
+function foo(o) {
+    let props = Object.getOwnPropertyNames(o);
+    for (let i = 0; i < props.length; ++i) {
+        let s = props[i];
+        assert(o.hasOwnProperty(s));
+    }
+}
+noInline(foo);
+
+let start = Date.now();
+for (let o of objs) {
+    foo(o);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);

Added: trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js (0 => 206136)


--- trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js	                        (rev 0)
+++ trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js	2016-09-20 01:05:50 UTC (rev 206136)
@@ -0,0 +1,34 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.");
+}
+noInline(assert);
+
+let objs = [];
+let symbolPool = [];
+const numSymbols = 800;
+for (let i = 0; i < numSymbols; ++i)
+    symbolPool.push(Symbol());
+
+for (let i = 0; i < 10000; i++) {
+    let num = (Math.random() * numSymbols) | 0;
+    let o = {};
+    for (let i = 0; i < num; ++i) {
+        o[symbolPool[i]] = 25; 
+    }
+    objs.push(o);
+}
+
+function foo(o) {
+    let props = Object.getOwnPropertySymbols(o);
+    for (let i = 0; i < props.length; ++i) {
+        let s = props[i];
+        assert(o.hasOwnProperty(s));
+    }
+}
+noInline(foo);
+
+let start = Date.now();
+for (let o of objs) {
+    foo(o);
+}

Added: trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js (0 => 206136)


--- trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js	                        (rev 0)
+++ trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js	2016-09-20 01:05:50 UTC (rev 206136)
@@ -0,0 +1,45 @@
+
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.");
+}
+noInline(assert);
+
+let objs = [];
+let keyPool = [];
+let symbolPool = [];
+const numKeys = 500;
+for (let i = 0; i < numKeys; ++i) {
+    keyPool.push(i + "foo");
+    symbolPool.push(Symbol("Foo"));
+}
+
+for (let i = 0; i < 10000; i++) {
+    let num = (Math.random() * numKeys) | 0;
+    let o = {};
+    for (let i = 0; i < num; ++i) {
+        o[keyPool[i]] = 25; 
+        o[symbolPool[i]] = 40; 
+    }
+    objs.push(o);
+}
+
+let time = 0;
+function foo(o) {
+    let props = Object.getOwnPropertyNames(o);
+    props.push(...Object.getOwnPropertySymbols(o));
+    let start = Date.now();
+    for (let i = 0; i < props.length; ++i) {
+        let s = props[i];
+        assert(o.hasOwnProperty(s));
+    }
+    time += Date.now() - start;
+}
+noInline(foo);
+
+for (let o of objs) {
+    foo(o);
+}
+const verbose = false;
+if (verbose)
+    print(time);

Modified: trunk/Source/_javascript_Core/ChangeLog (206135 => 206136)


--- trunk/Source/_javascript_Core/ChangeLog	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-09-20 01:05:50 UTC (rev 206136)
@@ -1,3 +1,90 @@
+2016-09-19  Saam Barati  <sbar...@apple.com>
+
+        Make HasOwnProperty faster
+        https://bugs.webkit.org/show_bug.cgi?id=161708
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds a cache for HasOwnProperty. The cache holds tuples
+        of {StructureID, UniquedStringImpl*, boolean} where the boolean indicates
+        the result of performing hasOwnProperty on an object with StructureID and
+        UniquedStringImpl*. If the cache contains an item, we can be guaranteed
+        that it contains the same result as performing hasOwnProperty on an
+        object O with a given structure and key. To guarantee this, we only add
+        items into the cache when the Structure of the given item is cacheable.
+
+        The caching strategy is simple: when adding new items into the cache,
+        we will evict any item that was in the location that the new item
+        is hashed into. We also clear the cache on every GC. This strategy
+        proves to be successful on speedometer, which sees a cache hit rate
+        over 90%. This caching strategy is now inlined into the DFG/FTL JITs
+        by now recognizing hasOwnProperty as an intrinsic with the corresponding
+        HasOwnProperty node. The goal of the node is to emit inlined code for
+        the cache lookup to prevent the overhead of the call for the common
+        case where we get a cache hit.
+
+        I'm seeing around a 1% to 1.5% percent improvement on Speedometer on
+        my machine. Hopefully the perf bots agree with my machine.
+
+        This patch also speeds up the microbenchmark I added by 2.5x.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
+        * heap/Heap.cpp:
+        (JSC::Heap::collectImpl):
+        * jit/JITOperations.h:
+        * runtime/HasOwnPropertyCache.h: Added.
+        (JSC::HasOwnPropertyCache::Entry::offsetOfStructureID):
+        (JSC::HasOwnPropertyCache::Entry::offsetOfImpl):
+        (JSC::HasOwnPropertyCache::Entry::offsetOfResult):
+        (JSC::HasOwnPropertyCache::operator delete):
+        (JSC::HasOwnPropertyCache::create):
+        (JSC::HasOwnPropertyCache::hash):
+        (JSC::HasOwnPropertyCache::get):
+        (JSC::HasOwnPropertyCache::tryAdd):
+        (JSC::HasOwnPropertyCache::clear):
+        (JSC::VM::ensureHasOwnPropertyCache):
+        * runtime/Intrinsic.h:
+        * runtime/JSObject.h:
+        * runtime/JSObjectInlines.h:
+        (JSC::JSObject::hasOwnProperty):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::ObjectPrototype::finishCreation):
+        (JSC::objectProtoFuncHasOwnProperty):
+        * runtime/Symbol.h:
+        * runtime/VM.cpp:
+        * runtime/VM.h:
+        (JSC::VM::hasOwnPropertyCache):
+
 2016-09-19  Benjamin Poulain  <bpoul...@apple.com>
 
         [JSC] Make the rounding-related nodes support any type

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (206135 => 206136)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-09-20 01:05:50 UTC (rev 206136)
@@ -1334,6 +1334,7 @@
 		79CFC6F01C33B10000C768EA /* LLIntPCRanges.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		79D5CD5A1C1106A900CECA07 /* SamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */; };
 		79D5CD5B1C1106A900CECA07 /* SamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 79D5CD591C1106A900CECA07 /* SamplingProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */; };
 		79EE0C001B4AFB85000385C9 /* VariableEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		79F8FC1E1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79F8FC1C1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp */; };
@@ -3578,6 +3579,7 @@
 		79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntPCRanges.h; path = llint/LLIntPCRanges.h; sourceTree = "<group>"; };
 		79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingProfiler.cpp; sourceTree = "<group>"; };
 		79D5CD591C1106A900CECA07 /* SamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingProfiler.h; sourceTree = "<group>"; };
+		79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HasOwnPropertyCache.h; sourceTree = "<group>"; };
 		79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableEnvironment.cpp; sourceTree = "<group>"; };
 		79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableEnvironment.h; sourceTree = "<group>"; };
 		79F8FC1C1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMaximalFlushInsertionPhase.cpp; path = dfg/DFGMaximalFlushInsertionPhase.cpp; sourceTree = "<group>"; };
@@ -5805,6 +5807,7 @@
 				BC337BDE0E1AF0B80076918A /* GetterSetter.h */,
 				79A0907D1D768465008B889B /* HashMapImpl.cpp */,
 				79A0907E1D768465008B889B /* HashMapImpl.h */,
+				79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */,
 				933A349D038AE80F008635CE /* Identifier.cpp */,
 				933A349A038AE7C6008635CE /* Identifier.h */,
 				8606DDE918DA44AB00A383D0 /* IdentifierInlines.h */,
@@ -8288,6 +8291,7 @@
 				0FF42748158EBE91004CB9FF /* udis86_syn.h in Headers */,
 				0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */,
 				A7E5AB391799E4B200D2833D /* UDis86Disassembler.h in Headers */,
+				79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */,
 				A7A8AF4117ADB5F3005AB174 /* Uint16Array.h in Headers */,
 				866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */,
 				A7A8AF4217ADB5F3005AB174 /* Uint32Array.h in Headers */,

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -2665,6 +2665,12 @@
         forNode(node).setType(SpecBoolean);
         break;
     }
+
+    case HasOwnProperty: {
+        clobberWorld(node->origin.semantic, clobberLimit);
+        forNode(node).setType(SpecBoolean);
+        break;
+    }
             
     case GetEnumerableLength: {
         forNode(node).setType(SpecInt32Only);

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -2561,6 +2561,26 @@
         return true;
     }
 
+    case HasOwnPropertyIntrinsic: {
+        if (argumentCountIncludingThis != 2)
+            return false;
+
+        // This can be racy, that's fine. We know that once we observe that this is created,
+        // that it will never be destroyed until the VM is destroyed. It's unlikely that
+        // we'd ever get to the point where we inline this as an intrinsic without the
+        // cache being created, however, it's possible if we always throw exceptions inside
+        // hasOwnProperty.
+        if (!m_vm->hasOwnPropertyCache())
+            return false;
+
+        insertChecks();
+        Node* object = get(virtualRegisterForArgument(0, registerOffset));
+        Node* key = get(virtualRegisterForArgument(1, registerOffset));
+        Node* result = addToGraph(HasOwnProperty, object, key);
+        set(VirtualRegister(resultOperand), result);
+        return true;
+    }
+
     default:
         return false;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -501,6 +501,7 @@
     case ConstructForwardVarargs:
     case ToPrimitive:
     case In:
+    case HasOwnProperty:
     case ValueAdd:
     case SetFunctionName:
     case GetDynamicVar:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -173,6 +173,7 @@
     case ToString:
     case CallStringConstructor:
     case In:
+    case HasOwnProperty:
     case Jump:
     case Branch:
     case Switch:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -1311,6 +1311,22 @@
             break;
         }
 
+        case HasOwnProperty: {
+            fixEdge<ObjectUse>(node->child1());
+#if CPU(X86) && USE(JSVALUE32_64)
+            // We don't have enough registers to do anything interesting on x86.
+            fixEdge<UntypedUse>(node->child2());
+#else
+            if (node->child2()->shouldSpeculateString())
+                fixEdge<StringUse>(node->child2());
+            else if (node->child2()->shouldSpeculateSymbol())
+                fixEdge<SymbolUse>(node->child2());
+            else
+                fixEdge<UntypedUse>(node->child2());
+#endif
+            break;
+        }
+
         case Check: {
             m_graph.doToChildren(
                 node,

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -331,6 +331,7 @@
     macro(ProfileType, NodeMustGenerate) \
     macro(ProfileControlFlow, NodeMustGenerate) \
     macro(SetFunctionName, NodeMustGenerate) \
+    macro(HasOwnProperty, NodeResultBoolean) \
     \
     macro(CreateActivation, NodeResultJS) \
     \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -42,6 +42,7 @@
 #include "FTLForOSREntryJITCode.h"
 #include "FTLOSREntry.h"
 #include "GetterSetter.h"
+#include "HasOwnPropertyCache.h"
 #include "HostCallReturnValue.h"
 #include "Interpreter.h"
 #include "JIT.h"
@@ -1673,6 +1674,28 @@
     return sizeOfVarargs(exec, arguments, firstVarArgOffset);
 }
 
+int32_t JIT_OPERATION operationHasOwnProperty(ExecState* exec, JSObject* thisObject, EncodedJSValue encodedKey)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue key = JSValue::decode(encodedKey);
+    Identifier propertyName = key.toPropertyKey(exec);
+    if (UNLIKELY(scope.exception()))
+        return false;
+
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
+    bool result = thisObject->hasOwnProperty(exec, propertyName.impl(), slot);
+    if (UNLIKELY(scope.exception()))
+        return false;
+
+    HasOwnPropertyCache* hasOwnPropertyCache = vm.hasOwnPropertyCache();
+    ASSERT(hasOwnPropertyCache);
+    hasOwnPropertyCache->tryAdd(vm, slot, thisObject, propertyName.impl(), result);
+    return result;
+}
+
 void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -177,6 +177,8 @@
 int32_t JIT_OPERATION operationSizeOfVarargs(ExecState*, EncodedJSValue arguments, int32_t firstVarArgOffset);
 void JIT_OPERATION operationLoadVarargs(ExecState*, int32_t firstElementDest, EncodedJSValue arguments, int32_t offset, int32_t length, int32_t mandatoryMinimum);
 
+int32_t JIT_OPERATION operationHasOwnProperty(ExecState*, JSObject*, EncodedJSValue);
+
 JSCell* JIT_OPERATION operationResolveScope(ExecState*, JSScope*, UniquedStringImpl*);
 EncodedJSValue JIT_OPERATION operationGetDynamicVar(ExecState*, JSObject* scope, UniquedStringImpl*, unsigned);
 void JIT_OPERATION operationPutDynamicVar(ExecState*, JSObject* scope, EncodedJSValue, UniquedStringImpl*, unsigned);

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -910,6 +910,10 @@
             setPrediction(SpecBoolean);
             break;
 
+        case HasOwnProperty:
+            setPrediction(SpecBoolean);
+            break;
+
         case GetEnumerableLength: {
             setPrediction(SpecInt32Only);
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -284,6 +284,7 @@
     case NewStringObject:
     case MakeRope:
     case In:
+    case HasOwnProperty:
     case CreateActivation:
     case CreateDirectArguments:
     case CreateScopedArguments:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -982,6 +982,11 @@
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(index), arg1);
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(Z_JITOperation_EOI operation, GPRReg result, GPRReg obj, GPRReg impl)
+    {
+        m_jit.setupArgumentsWithExecState(obj, impl);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(P_JITOperation_ESt operation, GPRReg result, Structure* structure)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
@@ -1309,19 +1314,21 @@
 
 
 #if USE(JSVALUE64)
-
+    JITCompiler::Call callOperation(Z_JITOperation_EOJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result);
     }
-
     JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC)
     {
         m_jit.setupArgumentsWithExecState(arg1.gpr(), arg2.gpr(), mathIC);
         return appendCallSetResult(operation, result.gpr());
     }
-
     JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg result, GPRReg arg1, GPRReg arg2, UniquedStringImpl* uid)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(uid));
@@ -1749,7 +1756,11 @@
         return appendCallSetResult(operation, result);
     }
 #else // USE(JSVALUE32_64)
-
+    JITCompiler::Call callOperation(Z_JITOperation_EOJ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR());
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2, GPRReg arg3)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), arg3);
@@ -3522,6 +3533,8 @@
 };
 
 class SpeculateCellOperand {
+    WTF_MAKE_NONCOPYABLE(SpeculateCellOperand);
+
 public:
     explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
         : m_jit(jit)
@@ -3536,6 +3549,16 @@
             gpr();
     }
 
+    explicit SpeculateCellOperand(SpeculateCellOperand&& other)
+    {
+        m_jit = other.m_jit;
+        m_edge = other.m_edge;
+        m_gprOrInvalid = other.m_gprOrInvalid;
+
+        other.m_gprOrInvalid = InvalidGPRReg;
+        other.m_edge = Edge();
+    }
+
     ~SpeculateCellOperand()
     {
         if (!m_edge)

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -37,6 +37,7 @@
 #include "DFGSlowPathGenerator.h"
 #include "DirectArguments.h"
 #include "GetterSetter.h"
+#include "HasOwnPropertyCache.h"
 #include "HashMapImpl.h"
 #include "JSEnvironmentRecord.h"
 #include "JSLexicalEnvironment.h"
@@ -4888,6 +4889,122 @@
         compileIn(node);
         break;
 
+    case HasOwnProperty: {
+#if CPU(X86)
+        ASSERT(node->child2().useKind() == UntypedUse);
+        SpeculateCellOperand object(this, node->child1());
+        JSValueOperand key(this, node->child2());
+        GPRTemporary result(this, Reuse, object);
+
+        JSValueRegs keyRegs = key.jsValueRegs();
+        GPRReg objectGPR = object.gpr();
+        GPRReg resultGPR = result.gpr();
+        flushRegisters();
+        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyRegs);
+        booleanResult(resultGPR, node);
+#else
+        SpeculateCellOperand object(this, node->child1());
+        GPRTemporary uniquedStringImpl(this);
+        GPRTemporary temp(this);
+        GPRTemporary hash(this);
+        GPRTemporary structureID(this);
+        GPRTemporary result(this);
+
+        Optional<SpeculateCellOperand> keyAsCell;
+        Optional<JSValueOperand> keyAsValue;
+        JSValueRegs keyRegs;
+        if (node->child2().useKind() == UntypedUse) {
+            keyAsValue = JSValueOperand(this, node->child2());
+            keyRegs = keyAsValue->jsValueRegs();
+        } else {
+            ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == SymbolUse);
+            keyAsCell = SpeculateCellOperand(this, node->child2());
+            keyRegs = JSValueRegs::payloadOnly(keyAsCell->gpr());
+        }
+
+        GPRReg objectGPR = object.gpr();
+        GPRReg implGPR = uniquedStringImpl.gpr();
+        GPRReg tempGPR = temp.gpr();
+        GPRReg hashGPR = hash.gpr();
+        GPRReg structureIDGPR = structureID.gpr();
+        GPRReg resultGPR = result.gpr();
+
+        speculateObject(node->child1());
+
+        MacroAssembler::JumpList slowPath;
+        switch (node->child2().useKind()) {
+        case SymbolUse: {
+            speculateSymbol(node->child2(), keyRegs.payloadGPR());
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), Symbol::offsetOfSymbolImpl()), implGPR);
+            break;
+        }
+        case StringUse: {
+            speculateString(node->child2(), keyRegs.payloadGPR());
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            break;
+        }
+        case UntypedUse: {
+            slowPath.append(m_jit.branchIfNotCell(keyRegs));
+            auto isNotString = m_jit.branchIfNotString(keyRegs.payloadGPR());
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            auto hasUniquedImpl = m_jit.jump();
+
+            isNotString.link(&m_jit);
+            slowPath.append(m_jit.branchIfNotSymbol(keyRegs.payloadGPR()));
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), Symbol::offsetOfSymbolImpl()), implGPR);
+
+            hasUniquedImpl.link(&m_jit);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
+        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
+        // ever load the result from the cache if the cache entry matches what we are querying for.
+        // So we either get super lucky and use zero for the hash and somehow collide with the entity
+        // we're looking for, or we realize we're comparing against another entity, and go to the
+        // slow path anyways.
+        m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
+        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
+        m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
+        m_jit.add32(structureIDGPR, hashGPR);
+        m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
+        m_jit.mul32(TrustedImm32(sizeof(HasOwnPropertyCache::Entry)), hashGPR, hashGPR);
+        ASSERT(m_jit.vm()->hasOwnPropertyCache());
+        m_jit.move(TrustedImmPtr(m_jit.vm()->hasOwnPropertyCache()), tempGPR);
+        slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual, 
+            MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
+        m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
+        m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
+        slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
+        auto done = m_jit.jump();
+
+        slowPath.link(&m_jit);
+        silentSpillAllRegisters(resultGPR);
+        if (node->child2().useKind() != UntypedUse) {
+            m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), tempGPR);
+            keyRegs = JSValueRegs(tempGPR, keyRegs.payloadGPR());
+        }
+        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyRegs);
+        silentFillAllRegisters(resultGPR);
+        m_jit.exceptionCheck();
+
+        done.link(&m_jit);
+        booleanResult(resultGPR, node);
+#endif // CPU(X86)
+        break;
+    }
+
     case StoreBarrier: {
         compileStoreBarrier(node);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -36,6 +36,7 @@
 #include "DFGSlowPathGenerator.h"
 #include "DirectArguments.h"
 #include "GetterSetter.h"
+#include "HasOwnPropertyCache.h"
 #include "JSCInlines.h"
 #include "JSEnvironmentRecord.h"
 #include "JSLexicalEnvironment.h"
@@ -4628,7 +4629,7 @@
         m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
         m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
-        m_jit.urshift64(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
+        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
         slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
         done.append(m_jit.jump());
 
@@ -4935,6 +4936,106 @@
     case In:
         compileIn(node);
         break;
+
+    case HasOwnProperty: {
+        SpeculateCellOperand object(this, node->child1());
+        GPRTemporary uniquedStringImpl(this);
+        GPRTemporary temp(this);
+        GPRTemporary hash(this);
+        GPRTemporary structureID(this);
+        GPRTemporary result(this);
+
+        Optional<SpeculateCellOperand> keyAsCell;
+        Optional<JSValueOperand> keyAsValue;
+        GPRReg keyGPR;
+        if (node->child2().useKind() == UntypedUse) {
+            keyAsValue = JSValueOperand(this, node->child2());
+            keyGPR = keyAsValue->gpr();
+        } else {
+            ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == SymbolUse);
+            keyAsCell = SpeculateCellOperand(this, node->child2());
+            keyGPR = keyAsCell->gpr();
+        }
+
+        GPRReg objectGPR = object.gpr();
+        GPRReg implGPR = uniquedStringImpl.gpr();
+        GPRReg tempGPR = temp.gpr();
+        GPRReg hashGPR = hash.gpr();
+        GPRReg structureIDGPR = structureID.gpr();
+        GPRReg resultGPR = result.gpr();
+
+        speculateObject(node->child1());
+
+        MacroAssembler::JumpList slowPath;
+        switch (node->child2().useKind()) {
+        case SymbolUse: {
+            speculateSymbol(node->child2(), keyGPR);
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
+            break;
+        }
+        case StringUse: {
+            speculateString(node->child2(), keyGPR);
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            break;
+        }
+        case UntypedUse: {
+            slowPath.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
+            auto isNotString = m_jit.branchIfNotString(keyGPR);
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            auto hasUniquedImpl = m_jit.jump();
+
+            isNotString.link(&m_jit);
+            slowPath.append(m_jit.branchIfNotSymbol(keyGPR));
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
+
+            hasUniquedImpl.link(&m_jit);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
+        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
+        // ever load the result from the cache if the cache entry matches what we are querying for.
+        // So we either get super lucky and use zero for the hash and somehow collide with the entity
+        // we're looking for, or we realize we're comparing against another entity, and go to the
+        // slow path anyways.
+        m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
+        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
+        m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
+        m_jit.add32(structureIDGPR, hashGPR);
+        m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
+        static_assert(sizeof(HasOwnPropertyCache::Entry) == 16, "Strong assumption of that here.");
+        m_jit.lshift32(TrustedImm32(4), hashGPR);
+        ASSERT(m_jit.vm()->hasOwnPropertyCache());
+        m_jit.move(TrustedImmPtr(m_jit.vm()->hasOwnPropertyCache()), tempGPR);
+        slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual, 
+            MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
+        m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
+        m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
+        slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
+        auto done = m_jit.jump();
+
+        slowPath.link(&m_jit);
+        silentSpillAllRegisters(resultGPR);
+        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyGPR);
+        silentFillAllRegisters(resultGPR);
+        m_jit.exceptionCheck();
+
+        done.link(&m_jit);
+        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
+        jsValueResult(resultGPR, node, DataFormatJSBoolean);
+        break;
+    }
         
     case CountExecution:
         m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node->executionCounter()->address()));

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -309,6 +309,10 @@
                     // while the inline one will not take a storage child at all.
                     // https://bugs.webkit.org/show_bug.cgi?id=159602
                     break;
+                case HasOwnProperty: {
+                    VALIDATE((node), !!m_graph.m_vm.hasOwnPropertyCache());
+                    break;
+                }
                 default:
                     break;
                 }

Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (206135 => 206136)


--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -31,9 +31,11 @@
 #include "B3Value.h"
 #include "DFGArrayMode.h"
 #include "FTLAbstractHeap.h"
+#include "HasOwnPropertyCache.h"
 #include "IndexingType.h"
 #include "JSMap.h"
 #include "JSSet.h"
+#include "Symbol.h"
 
 namespace JSC { namespace FTL {
 
@@ -110,6 +112,7 @@
     macro(HashMapImpl_buffer,  HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \
     macro(HashMapBucket_value, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()) \
     macro(HashMapBucket_key, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()) \
+    macro(Symbol_symbolImpl, Symbol::offsetOfSymbolImpl()) \
 
 #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
     macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \
@@ -128,7 +131,8 @@
     macro(scopedArgumentsTableArguments, 0, sizeof(int32_t)) \
     macro(singleCharacterStrings, 0, sizeof(JSString*)) \
     macro(structureTable, 0, sizeof(Structure*)) \
-    macro(variables, 0, sizeof(Register))
+    macro(variables, 0, sizeof(Register)) \
+    macro(HasOwnPropertyCache, 0, sizeof(HasOwnPropertyCache::Entry)) \
     
 #define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \
     macro(properties)

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -181,6 +181,7 @@
     case ThrowReferenceError:
     case Unreachable:
     case In:
+    case HasOwnProperty:
     case IsCellWithType:
     case MapHash:
     case GetMapBucket:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -632,6 +632,9 @@
         case In:
             compileIn();
             break;
+        case HasOwnProperty:
+            compileHasOwnProperty();
+            break;
         case PutById:
         case PutByIdDirect:
         case PutByIdFlush:
@@ -6772,6 +6775,108 @@
         setJSValue(vmCall(Int64, m_out.operation(operationGenericIn), m_callFrame, cell, lowJSValue(m_node->child1())));
     }
 
+    void compileHasOwnProperty()
+    {
+        LBasicBlock slowCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+        LBasicBlock lastNext = nullptr;
+
+        LValue object = lowObject(m_node->child1());
+        LValue uniquedStringImpl;
+        LValue keyAsValue = nullptr;
+        switch (m_node->child2().useKind()) {
+        case StringUse: {
+            LBasicBlock isNonEmptyString = m_out.newBlock();
+            LBasicBlock isAtomicString = m_out.newBlock();
+
+            keyAsValue = lowString(m_node->child2());
+            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
+            m_out.branch(m_out.notNull(uniquedStringImpl), usually(isNonEmptyString), rarely(slowCase));
+
+            lastNext = m_out.appendTo(isNonEmptyString, isAtomicString);
+            LValue isNotAtomic = m_out.testIsZero32(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
+            m_out.branch(isNotAtomic, rarely(slowCase), usually(isAtomicString));
+
+            m_out.appendTo(isAtomicString, slowCase);
+            break;
+        }
+        case SymbolUse: {
+            keyAsValue = lowSymbol(m_node->child2());
+            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.Symbol_symbolImpl);
+            lastNext = m_out.insertNewBlocksBefore(slowCase);
+            break;
+        }
+        case UntypedUse: {
+            LBasicBlock isCellCase = m_out.newBlock();
+            LBasicBlock isStringCase = m_out.newBlock();
+            LBasicBlock notStringCase = m_out.newBlock();
+            LBasicBlock isNonEmptyString = m_out.newBlock();
+            LBasicBlock isSymbolCase = m_out.newBlock();
+            LBasicBlock hasUniquedStringImpl = m_out.newBlock();
+
+            keyAsValue = lowJSValue(m_node->child2());
+            m_out.branch(isCell(keyAsValue), usually(isCellCase), rarely(slowCase));
+
+            lastNext = m_out.appendTo(isCellCase, isStringCase);
+            m_out.branch(isString(keyAsValue), unsure(isStringCase), unsure(notStringCase));
+
+            m_out.appendTo(isStringCase, isNonEmptyString);
+            LValue implFromString = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
+            ValueFromBlock stringResult = m_out.anchor(implFromString);
+            m_out.branch(m_out.notNull(implFromString), usually(isNonEmptyString), rarely(slowCase));
+
+            m_out.appendTo(isNonEmptyString, notStringCase);
+            LValue isNotAtomic = m_out.testIsZero32(m_out.load32(implFromString, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
+            m_out.branch(isNotAtomic, rarely(slowCase), usually(hasUniquedStringImpl));
+
+            m_out.appendTo(notStringCase, isSymbolCase);
+            m_out.branch(isSymbol(keyAsValue), unsure(isSymbolCase), unsure(slowCase));
+
+            m_out.appendTo(isSymbolCase, hasUniquedStringImpl);
+            ValueFromBlock symbolResult = m_out.anchor(m_out.loadPtr(keyAsValue, m_heaps.Symbol_symbolImpl));
+            m_out.jump(hasUniquedStringImpl);
+
+            m_out.appendTo(hasUniquedStringImpl, slowCase);
+            uniquedStringImpl = m_out.phi(pointerType(), stringResult, symbolResult);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        ASSERT(keyAsValue);
+
+        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
+        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
+        // ever load the result from the cache if the cache entry matches what we are querying for.
+        // So we either get super lucky and use zero for the hash and somehow collide with the entity
+        // we're looking for, or we realize we're comparing against another entity, and go to the
+        // slow path anyways.
+        LValue hash = m_out.lShr(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
+
+        LValue structureID = m_out.load32(object, m_heaps.JSCell_structureID);
+        LValue index = m_out.add(hash, structureID);
+        index = m_out.zeroExtPtr(m_out.bitAnd(index, m_out.constInt32(HasOwnPropertyCache::mask)));
+        ASSERT(vm().hasOwnPropertyCache());
+        LValue cache = m_out.constIntPtr(vm().hasOwnPropertyCache());
+
+        IndexedAbstractHeap& heap = m_heaps.HasOwnPropertyCache;
+        LValue sameStructureID = m_out.equal(structureID, m_out.load32(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfStructureID())));
+        LValue sameImpl = m_out.equal(uniquedStringImpl, m_out.loadPtr(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfImpl())));
+        ValueFromBlock fastResult = m_out.anchor(m_out.load8ZeroExt32(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfResult())));
+        LValue cacheHit = m_out.bitAnd(sameStructureID, sameImpl);
+
+        m_out.branch(m_out.notZero32(cacheHit), usually(continuation), rarely(slowCase));
+
+        m_out.appendTo(slowCase, continuation);
+        ValueFromBlock slowResult;
+        slowResult = m_out.anchor(vmCall(Int32, m_out.operation(operationHasOwnProperty), m_callFrame, object, keyAsValue));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setBoolean(m_out.phi(Int32, fastResult, slowResult));
+    }
+
     void compileOverridesHasInstance()
     {
         JSFunction* defaultHasInstanceFunction = jsCast<JSFunction*>(m_node->cellOperand()->value());

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -29,6 +29,7 @@
 #include "GCActivityCallback.h"
 #include "GCIncomingRefCountedSetInlines.h"
 #include "GCTypeMap.h"
+#include "HasOwnPropertyCache.h"
 #include "HeapHelperPool.h"
 #include "HeapIterationScope.h"
 #include "HeapProfiler.h"
@@ -1022,6 +1023,9 @@
         stopAllocation();
         prepareForMarking();
         flushWriteBarrierBuffer();
+
+        if (HasOwnPropertyCache* cache = vm()->hasOwnPropertyCache())
+            cache->clear();
     }
 
     markRoots(gcStartTime, stackOrigin, stackTop, calleeSavedRegisters);

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (206135 => 206136)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -221,6 +221,8 @@
 typedef int32_t (JIT_OPERATION *Z_JITOperation_EJOJ)(ExecState*, EncodedJSValue, JSObject*, EncodedJSValue);
 typedef int32_t (JIT_OPERATION *Z_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
 typedef int32_t (JIT_OPERATION *Z_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
+typedef int32_t (JIT_OPERATION *Z_JITOperation_EOI)(ExecState*, JSObject*, UniquedStringImpl*);
+typedef int32_t (JIT_OPERATION *Z_JITOperation_EOJ)(ExecState*, JSObject*, EncodedJSValue);
 typedef size_t (JIT_OPERATION *S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef size_t (JIT_OPERATION *S_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
 typedef size_t (JIT_OPERATION *S_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue);

Added: trunk/Source/_javascript_Core/runtime/HasOwnPropertyCache.h (0 => 206136)


--- trunk/Source/_javascript_Core/runtime/HasOwnPropertyCache.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/HasOwnPropertyCache.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include "JSProxy.h"
+#include "PropertySlot.h"
+#include "Structure.h"
+
+namespace JSC {
+
+class HasOwnPropertyCache {
+    static const uint32_t size = 2 * 1024;
+    static_assert(!(size & (size - 1)), "size should be a power of two.");
+public:
+    static const uint32_t mask = size - 1;
+
+    struct Entry {
+        static ptrdiff_t offsetOfStructureID() { return OBJECT_OFFSETOF(Entry, structureID); }
+        static ptrdiff_t offsetOfImpl() { return OBJECT_OFFSETOF(Entry, impl); }
+        static ptrdiff_t offsetOfResult() { return OBJECT_OFFSETOF(Entry, result); }
+
+        UniquedStringImpl* impl;
+        StructureID structureID;
+        bool result;
+    };
+
+    HasOwnPropertyCache() = delete;
+
+    void operator delete(void* cache)
+    {
+        fastFree(cache);
+    }
+
+    static HasOwnPropertyCache* create()
+    {
+        size_t allocationSize = sizeof(Entry) * size;
+        HasOwnPropertyCache* result = static_cast<HasOwnPropertyCache*>(fastMalloc(allocationSize));
+        result->clear();
+        return result;
+    }
+
+    ALWAYS_INLINE static uint32_t hash(StructureID structureID, UniquedStringImpl* impl)
+    {
+        return bitwise_cast<uint32_t>(structureID) + impl->hash();
+    }
+
+    ALWAYS_INLINE Optional<bool> get(Structure* structure, PropertyName propName)
+    {
+        UniquedStringImpl* impl = propName.uid();
+        StructureID id = structure->id();
+        uint32_t index = HasOwnPropertyCache::hash(id, impl) & mask;
+        Entry& entry = bitwise_cast<Entry*>(this)[index];
+        if (entry.structureID == id && entry.impl == impl)
+            return entry.result;
+        return Nullopt;
+    }
+
+    ALWAYS_INLINE void tryAdd(VM& vm, PropertySlot& slot, JSObject* object, PropertyName propName, bool result)
+    {
+        if (parseIndex(propName))
+            return;
+
+        if (!slot.isCacheable() && !slot.isUnset())
+            return;
+
+        if (object->type() == PureForwardingProxyType || object->type() == ImpureProxyType)
+            return;
+
+        Structure* structure = object->structure(vm);
+        if (!structure->typeInfo().prohibitsPropertyCaching()
+            && structure->propertyAccessesAreCacheable()
+            && (!slot.isUnset() || structure->propertyAccessesAreCacheableForAbsence())) {
+            if (structure->isDictionary()) {
+                if (structure->hasBeenFlattenedBefore())
+                    return;
+                object->flattenDictionaryObject(vm);
+            }
+
+            ASSERT(!result == slot.isUnset());
+
+            UniquedStringImpl* impl = propName.uid();
+            StructureID id = structure->id();
+            uint32_t index = HasOwnPropertyCache::hash(id, impl) & mask;
+            bitwise_cast<Entry*>(this)[index] = Entry{ impl, id, result };
+        }
+    }
+
+    void clear()
+    {
+        memset(this, 0, sizeof(Entry) * size);
+    }
+};
+
+ALWAYS_INLINE HasOwnPropertyCache* VM::ensureHasOwnPropertyCache()
+{
+    if (UNLIKELY(!m_hasOwnPropertyCache))
+        m_hasOwnPropertyCache = std::unique_ptr<HasOwnPropertyCache>(HasOwnPropertyCache::create());
+    return m_hasOwnPropertyCache.get();
+}
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -65,6 +65,7 @@
     JSMapGetIntrinsic,
     JSMapHasIntrinsic,
     JSSetHasIntrinsic,
+    HasOwnPropertyIntrinsic,
 
     // Getter intrinsics.
     TypedArrayLengthIntrinsic,

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -523,6 +523,7 @@
     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
     bool hasPropertyGeneric(ExecState*, PropertyName, PropertySlot::InternalMethodType) const;
     bool hasPropertyGeneric(ExecState*, unsigned propertyName, PropertySlot::InternalMethodType) const;
+    bool hasOwnProperty(ExecState*, PropertyName, PropertySlot&) const;
     bool hasOwnProperty(ExecState*, PropertyName) const;
     bool hasOwnProperty(ExecState*, unsigned) const;
 

Modified: trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/JSObjectInlines.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/JSObjectInlines.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -199,14 +199,20 @@
 
 // HasOwnProperty(O, P) from section 7.3.11 in the spec.
 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty
-ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
+ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
 {
-    PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+    ASSERT(slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty);
     if (LIKELY(const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot == JSObject::getOwnPropertySlot))
         return JSObject::getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
     return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
 }
 
+ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
+{
+    PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+    return hasOwnProperty(exec, propertyName, slot);
+}
+
 ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const
 {
     PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);

Modified: trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -23,6 +23,7 @@
 
 #include "Error.h"
 #include "GetterSetter.h"
+#include "HasOwnPropertyCache.h"
 #include "JSFunction.h"
 #include "JSString.h"
 #include "JSCInlines.h"
@@ -60,7 +61,7 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, DontEnum, 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1);
+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1, HasOwnPropertyIntrinsic);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->__defineGetter__, objectProtoFuncDefineGetter, DontEnum, 2);
@@ -97,9 +98,24 @@
     if (UNLIKELY(scope.exception()))
         return JSValue::encode(jsUndefined());
     JSObject* thisObject = thisValue.toObject(exec);
-    if (!thisObject)
+    if (UNLIKELY(!thisObject))
         return JSValue::encode(JSValue());
-    return JSValue::encode(jsBoolean(thisObject->hasOwnProperty(exec, propertyName)));
+
+    Structure* structure = thisObject->structure(vm);
+    HasOwnPropertyCache* hasOwnPropertyCache = vm.ensureHasOwnPropertyCache();
+    if (Optional<bool> result = hasOwnPropertyCache->get(structure, propertyName)) {
+        ASSERT(*result == thisObject->hasOwnProperty(exec, propertyName));
+        ASSERT(!scope.exception());
+        return JSValue::encode(jsBoolean(*result));
+    }
+
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
+    bool result = thisObject->hasOwnProperty(exec, propertyName, slot);
+    if (UNLIKELY(scope.exception()))
+        return JSValue::encode(jsUndefined());
+
+    hasOwnPropertyCache->tryAdd(vm, slot, thisObject, propertyName, result);
+    return JSValue::encode(jsBoolean(result));
 }
 
 EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)

Modified: trunk/Source/_javascript_Core/runtime/Symbol.h (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/Symbol.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/Symbol.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -59,6 +59,12 @@
     JSObject* toObject(ExecState*, JSGlobalObject*) const;
     double toNumber(ExecState*) const;
 
+    static ptrdiff_t offsetOfSymbolImpl()
+    {
+        // PrivateName is just a Ref<SymbolImpl> which can just be used as a SymbolImpl*.
+        return OBJECT_OFFSETOF(Symbol, m_privateName);
+    }
+
 protected:
     static void destroy(JSCell*);
 

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2016-09-20 01:05:50 UTC (rev 206136)
@@ -47,6 +47,7 @@
 #include "FunctionConstructor.h"
 #include "GCActivityCallback.h"
 #include "GetterSetter.h"
+#include "HasOwnPropertyCache.h"
 #include "Heap.h"
 #include "HeapIterationScope.h"
 #include "HeapProfiler.h"

Modified: trunk/Source/_javascript_Core/runtime/VM.h (206135 => 206136)


--- trunk/Source/_javascript_Core/runtime/VM.h	2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2016-09-20 01:05:50 UTC (rev 206136)
@@ -89,6 +89,7 @@
 class HandleStack;
 class TypeProfiler;
 class TypeProfilerLog;
+class HasOwnPropertyCache;
 class HeapProfiler;
 class Identifier;
 class Interpreter;
@@ -554,6 +555,10 @@
     BumpPointerAllocator m_regExpAllocator;
     ConcurrentJITLock m_regExpAllocatorLock;
 
+    std::unique_ptr<HasOwnPropertyCache> m_hasOwnPropertyCache;
+    ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.get(); }
+    HasOwnPropertyCache* ensureHasOwnPropertyCache();
+
 #if ENABLE(REGEXP_TRACING)
     typedef ListHashSet<RegExp*> RTTraceList;
     RTTraceList* m_rtTraceList;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to