Changeset 206136 in webkit


Ignore:
Timestamp:
Sep 19, 2016 6:05:50 PM (8 years ago)
Author:
sbarati@apple.com
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/JavaScriptCore:

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.

  • JavaScriptCore.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):

Location:
trunk
Files:
6 added
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r206134 r206136  
     12016-09-19  Saam Barati  <sbarati@apple.com>
     2
     3        Make HasOwnProperty faster
     4        https://bugs.webkit.org/show_bug.cgi?id=161708
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * microbenchmarks/has-own-property-name-cache.js: Added.
     9        (foo):
     10        * stress/has-own-property-cache-basics.js: Added.
     11        (assert):
     12        (foo):
     13        * stress/has-own-property-name-cache-string-keys.js: Added.
     14        (assert):
     15        (foo):
     16        * stress/has-own-property-name-cache-symbol-keys.js: Added.
     17        (assert):
     18        (foo):
     19        * stress/has-own-property-name-cache-symbols-and-strings.js: Added.
     20        (assert):
     21        (foo):
     22
    1232016-09-19  Benjamin Poulain  <bpoulain@apple.com>
    224
  • trunk/Source/JavaScriptCore/ChangeLog

    r206134 r206136  
     12016-09-19  Saam Barati  <sbarati@apple.com>
     2
     3        Make HasOwnProperty faster
     4        https://bugs.webkit.org/show_bug.cgi?id=161708
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch adds a cache for HasOwnProperty. The cache holds tuples
     9        of {StructureID, UniquedStringImpl*, boolean} where the boolean indicates
     10        the result of performing hasOwnProperty on an object with StructureID and
     11        UniquedStringImpl*. If the cache contains an item, we can be guaranteed
     12        that it contains the same result as performing hasOwnProperty on an
     13        object O with a given structure and key. To guarantee this, we only add
     14        items into the cache when the Structure of the given item is cacheable.
     15
     16        The caching strategy is simple: when adding new items into the cache,
     17        we will evict any item that was in the location that the new item
     18        is hashed into. We also clear the cache on every GC. This strategy
     19        proves to be successful on speedometer, which sees a cache hit rate
     20        over 90%. This caching strategy is now inlined into the DFG/FTL JITs
     21        by now recognizing hasOwnProperty as an intrinsic with the corresponding
     22        HasOwnProperty node. The goal of the node is to emit inlined code for
     23        the cache lookup to prevent the overhead of the call for the common
     24        case where we get a cache hit.
     25
     26        I'm seeing around a 1% to 1.5% percent improvement on Speedometer on
     27        my machine. Hopefully the perf bots agree with my machine.
     28
     29        This patch also speeds up the microbenchmark I added by 2.5x.
     30
     31        * JavaScriptCore.xcodeproj/project.pbxproj:
     32        * dfg/DFGAbstractInterpreterInlines.h:
     33        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     34        * dfg/DFGByteCodeParser.cpp:
     35        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     36        * dfg/DFGClobberize.h:
     37        (JSC::DFG::clobberize):
     38        * dfg/DFGDoesGC.cpp:
     39        (JSC::DFG::doesGC):
     40        * dfg/DFGFixupPhase.cpp:
     41        (JSC::DFG::FixupPhase::fixupNode):
     42        * dfg/DFGNodeType.h:
     43        * dfg/DFGOperations.cpp:
     44        * dfg/DFGOperations.h:
     45        * dfg/DFGPredictionPropagationPhase.cpp:
     46        * dfg/DFGSafeToExecute.h:
     47        (JSC::DFG::safeToExecute):
     48        * dfg/DFGSpeculativeJIT.h:
     49        (JSC::DFG::SpeculativeJIT::callOperation):
     50        (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
     51        * dfg/DFGSpeculativeJIT32_64.cpp:
     52        (JSC::DFG::SpeculativeJIT::compile):
     53        * dfg/DFGSpeculativeJIT64.cpp:
     54        (JSC::DFG::SpeculativeJIT::compile):
     55        * dfg/DFGValidate.cpp:
     56        * ftl/FTLAbstractHeapRepository.h:
     57        * ftl/FTLCapabilities.cpp:
     58        (JSC::FTL::canCompile):
     59        * ftl/FTLLowerDFGToB3.cpp:
     60        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     61        (JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
     62        * heap/Heap.cpp:
     63        (JSC::Heap::collectImpl):
     64        * jit/JITOperations.h:
     65        * runtime/HasOwnPropertyCache.h: Added.
     66        (JSC::HasOwnPropertyCache::Entry::offsetOfStructureID):
     67        (JSC::HasOwnPropertyCache::Entry::offsetOfImpl):
     68        (JSC::HasOwnPropertyCache::Entry::offsetOfResult):
     69        (JSC::HasOwnPropertyCache::operator delete):
     70        (JSC::HasOwnPropertyCache::create):
     71        (JSC::HasOwnPropertyCache::hash):
     72        (JSC::HasOwnPropertyCache::get):
     73        (JSC::HasOwnPropertyCache::tryAdd):
     74        (JSC::HasOwnPropertyCache::clear):
     75        (JSC::VM::ensureHasOwnPropertyCache):
     76        * runtime/Intrinsic.h:
     77        * runtime/JSObject.h:
     78        * runtime/JSObjectInlines.h:
     79        (JSC::JSObject::hasOwnProperty):
     80        * runtime/ObjectPrototype.cpp:
     81        (JSC::ObjectPrototype::finishCreation):
     82        (JSC::objectProtoFuncHasOwnProperty):
     83        * runtime/Symbol.h:
     84        * runtime/VM.cpp:
     85        * runtime/VM.h:
     86        (JSC::VM::hasOwnPropertyCache):
     87
    1882016-09-19  Benjamin Poulain  <bpoulain@apple.com>
    289
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r206110 r206136  
    13351335                79D5CD5A1C1106A900CECA07 /* SamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */; };
    13361336                79D5CD5B1C1106A900CECA07 /* SamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 79D5CD591C1106A900CECA07 /* SamplingProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1337                79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
    13371338                79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */; };
    13381339                79EE0C001B4AFB85000385C9 /* VariableEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    35793580                79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingProfiler.cpp; sourceTree = "<group>"; };
    35803581                79D5CD591C1106A900CECA07 /* SamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingProfiler.h; sourceTree = "<group>"; };
     3582                79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HasOwnPropertyCache.h; sourceTree = "<group>"; };
    35813583                79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableEnvironment.cpp; sourceTree = "<group>"; };
    35823584                79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableEnvironment.h; sourceTree = "<group>"; };
     
    58065808                                79A0907D1D768465008B889B /* HashMapImpl.cpp */,
    58075809                                79A0907E1D768465008B889B /* HashMapImpl.h */,
     5810                                79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */,
    58085811                                933A349D038AE80F008635CE /* Identifier.cpp */,
    58095812                                933A349A038AE7C6008635CE /* Identifier.h */,
     
    82898292                                0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */,
    82908293                                A7E5AB391799E4B200D2833D /* UDis86Disassembler.h in Headers */,
     8294                                79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */,
    82918295                                A7A8AF4117ADB5F3005AB174 /* Uint16Array.h in Headers */,
    82928296                                866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */,
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r206134 r206136  
    26662666        break;
    26672667    }
     2668
     2669    case HasOwnProperty: {
     2670        clobberWorld(node->origin.semantic, clobberLimit);
     2671        forNode(node).setType(SpecBoolean);
     2672        break;
     2673    }
    26682674           
    26692675    case GetEnumerableLength: {
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r206134 r206136  
    25582558        Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(key), Edge(hash));
    25592559        Node* result = addToGraph(IsNonEmptyMapBucket, bucket);
     2560        set(VirtualRegister(resultOperand), result);
     2561        return true;
     2562    }
     2563
     2564    case HasOwnPropertyIntrinsic: {
     2565        if (argumentCountIncludingThis != 2)
     2566            return false;
     2567
     2568        // This can be racy, that's fine. We know that once we observe that this is created,
     2569        // that it will never be destroyed until the VM is destroyed. It's unlikely that
     2570        // we'd ever get to the point where we inline this as an intrinsic without the
     2571        // cache being created, however, it's possible if we always throw exceptions inside
     2572        // hasOwnProperty.
     2573        if (!m_vm->hasOwnPropertyCache())
     2574            return false;
     2575
     2576        insertChecks();
     2577        Node* object = get(virtualRegisterForArgument(0, registerOffset));
     2578        Node* key = get(virtualRegisterForArgument(1, registerOffset));
     2579        Node* result = addToGraph(HasOwnProperty, object, key);
    25602580        set(VirtualRegister(resultOperand), result);
    25612581        return true;
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r206134 r206136  
    502502    case ToPrimitive:
    503503    case In:
     504    case HasOwnProperty:
    504505    case ValueAdd:
    505506    case SetFunctionName:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r206098 r206136  
    174174    case CallStringConstructor:
    175175    case In:
     176    case HasOwnProperty:
    176177    case Jump:
    177178    case Branch:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r206134 r206136  
    13091309           
    13101310            fixEdge<CellUse>(node->child2());
     1311            break;
     1312        }
     1313
     1314        case HasOwnProperty: {
     1315            fixEdge<ObjectUse>(node->child1());
     1316#if CPU(X86) && USE(JSVALUE32_64)
     1317            // We don't have enough registers to do anything interesting on x86.
     1318            fixEdge<UntypedUse>(node->child2());
     1319#else
     1320            if (node->child2()->shouldSpeculateString())
     1321                fixEdge<StringUse>(node->child2());
     1322            else if (node->child2()->shouldSpeculateSymbol())
     1323                fixEdge<SymbolUse>(node->child2());
     1324            else
     1325                fixEdge<UntypedUse>(node->child2());
     1326#endif
    13111327            break;
    13121328        }
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r206134 r206136  
    332332    macro(ProfileControlFlow, NodeMustGenerate) \
    333333    macro(SetFunctionName, NodeMustGenerate) \
     334    macro(HasOwnProperty, NodeResultBoolean) \
    334335    \
    335336    macro(CreateActivation, NodeResultJS) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r206134 r206136  
    4343#include "FTLOSREntry.h"
    4444#include "GetterSetter.h"
     45#include "HasOwnPropertyCache.h"
    4546#include "HostCallReturnValue.h"
    4647#include "Interpreter.h"
     
    16741675}
    16751676
     1677int32_t JIT_OPERATION operationHasOwnProperty(ExecState* exec, JSObject* thisObject, EncodedJSValue encodedKey)
     1678{
     1679    VM& vm = exec->vm();
     1680    NativeCallFrameTracer tracer(&vm, exec);
     1681    auto scope = DECLARE_THROW_SCOPE(vm);
     1682
     1683    JSValue key = JSValue::decode(encodedKey);
     1684    Identifier propertyName = key.toPropertyKey(exec);
     1685    if (UNLIKELY(scope.exception()))
     1686        return false;
     1687
     1688    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
     1689    bool result = thisObject->hasOwnProperty(exec, propertyName.impl(), slot);
     1690    if (UNLIKELY(scope.exception()))
     1691        return false;
     1692
     1693    HasOwnPropertyCache* hasOwnPropertyCache = vm.hasOwnPropertyCache();
     1694    ASSERT(hasOwnPropertyCache);
     1695    hasOwnPropertyCache->tryAdd(vm, slot, thisObject, propertyName.impl(), result);
     1696    return result;
     1697}
     1698
    16761699void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum)
    16771700{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r206134 r206136  
    178178void JIT_OPERATION operationLoadVarargs(ExecState*, int32_t firstElementDest, EncodedJSValue arguments, int32_t offset, int32_t length, int32_t mandatoryMinimum);
    179179
     180int32_t JIT_OPERATION operationHasOwnProperty(ExecState*, JSObject*, EncodedJSValue);
     181
    180182JSCell* JIT_OPERATION operationResolveScope(ExecState*, JSScope*, UniquedStringImpl*);
    181183EncodedJSValue JIT_OPERATION operationGetDynamicVar(ExecState*, JSObject* scope, UniquedStringImpl*, unsigned);
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r206134 r206136  
    908908
    909909        case In:
     910            setPrediction(SpecBoolean);
     911            break;
     912
     913        case HasOwnProperty:
    910914            setPrediction(SpecBoolean);
    911915            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r206098 r206136  
    285285    case MakeRope:
    286286    case In:
     287    case HasOwnProperty:
    287288    case CreateActivation:
    288289    case CreateDirectArguments:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r206065 r206136  
    983983        return appendCallSetResult(operation, result);
    984984    }
     985    JITCompiler::Call callOperation(Z_JITOperation_EOI operation, GPRReg result, GPRReg obj, GPRReg impl)
     986    {
     987        m_jit.setupArgumentsWithExecState(obj, impl);
     988        return appendCallSetResult(operation, result);
     989    }
    985990    JITCompiler::Call callOperation(P_JITOperation_ESt operation, GPRReg result, Structure* structure)
    986991    {
     
    13101315
    13111316#if USE(JSVALUE64)
    1312 
     1317    JITCompiler::Call callOperation(Z_JITOperation_EOJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1318    {
     1319        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1320        return appendCallSetResult(operation, result);
     1321    }
    13131322    JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    13141323    {
     
    13161325        return appendCallSetResult(operation, result);
    13171326    }
    1318 
    13191327    JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC)
    13201328    {
     
    13221330        return appendCallSetResult(operation, result.gpr());
    13231331    }
    1324 
    13251332    JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg result, GPRReg arg1, GPRReg arg2, UniquedStringImpl* uid)
    13261333    {
     
    17501757    }
    17511758#else // USE(JSVALUE32_64)
    1752 
     1759    JITCompiler::Call callOperation(Z_JITOperation_EOJ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2)
     1760    {
     1761        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR());
     1762        return appendCallSetResult(operation, result);
     1763    }
    17531764    JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2, GPRReg arg3)
    17541765    {
     
    35233534
    35243535class SpeculateCellOperand {
     3536    WTF_MAKE_NONCOPYABLE(SpeculateCellOperand);
     3537
    35253538public:
    35263539    explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
     
    35353548        if (jit->isFilled(node()))
    35363549            gpr();
     3550    }
     3551
     3552    explicit SpeculateCellOperand(SpeculateCellOperand&& other)
     3553    {
     3554        m_jit = other.m_jit;
     3555        m_edge = other.m_edge;
     3556        m_gprOrInvalid = other.m_gprOrInvalid;
     3557
     3558        other.m_gprOrInvalid = InvalidGPRReg;
     3559        other.m_edge = Edge();
    35373560    }
    35383561
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r206098 r206136  
    3838#include "DirectArguments.h"
    3939#include "GetterSetter.h"
     40#include "HasOwnPropertyCache.h"
    4041#include "HashMapImpl.h"
    4142#include "JSEnvironmentRecord.h"
     
    48894890        break;
    48904891
     4892    case HasOwnProperty: {
     4893#if CPU(X86)
     4894        ASSERT(node->child2().useKind() == UntypedUse);
     4895        SpeculateCellOperand object(this, node->child1());
     4896        JSValueOperand key(this, node->child2());
     4897        GPRTemporary result(this, Reuse, object);
     4898
     4899        JSValueRegs keyRegs = key.jsValueRegs();
     4900        GPRReg objectGPR = object.gpr();
     4901        GPRReg resultGPR = result.gpr();
     4902        flushRegisters();
     4903        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyRegs);
     4904        booleanResult(resultGPR, node);
     4905#else
     4906        SpeculateCellOperand object(this, node->child1());
     4907        GPRTemporary uniquedStringImpl(this);
     4908        GPRTemporary temp(this);
     4909        GPRTemporary hash(this);
     4910        GPRTemporary structureID(this);
     4911        GPRTemporary result(this);
     4912
     4913        Optional<SpeculateCellOperand> keyAsCell;
     4914        Optional<JSValueOperand> keyAsValue;
     4915        JSValueRegs keyRegs;
     4916        if (node->child2().useKind() == UntypedUse) {
     4917            keyAsValue = JSValueOperand(this, node->child2());
     4918            keyRegs = keyAsValue->jsValueRegs();
     4919        } else {
     4920            ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == SymbolUse);
     4921            keyAsCell = SpeculateCellOperand(this, node->child2());
     4922            keyRegs = JSValueRegs::payloadOnly(keyAsCell->gpr());
     4923        }
     4924
     4925        GPRReg objectGPR = object.gpr();
     4926        GPRReg implGPR = uniquedStringImpl.gpr();
     4927        GPRReg tempGPR = temp.gpr();
     4928        GPRReg hashGPR = hash.gpr();
     4929        GPRReg structureIDGPR = structureID.gpr();
     4930        GPRReg resultGPR = result.gpr();
     4931
     4932        speculateObject(node->child1());
     4933
     4934        MacroAssembler::JumpList slowPath;
     4935        switch (node->child2().useKind()) {
     4936        case SymbolUse: {
     4937            speculateSymbol(node->child2(), keyRegs.payloadGPR());
     4938            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), Symbol::offsetOfSymbolImpl()), implGPR);
     4939            break;
     4940        }
     4941        case StringUse: {
     4942            speculateString(node->child2(), keyRegs.payloadGPR());
     4943            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
     4944            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
     4945            slowPath.append(m_jit.branchTest32(
     4946                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
     4947                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
     4948            break;
     4949        }
     4950        case UntypedUse: {
     4951            slowPath.append(m_jit.branchIfNotCell(keyRegs));
     4952            auto isNotString = m_jit.branchIfNotString(keyRegs.payloadGPR());
     4953            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
     4954            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
     4955            slowPath.append(m_jit.branchTest32(
     4956                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
     4957                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
     4958            auto hasUniquedImpl = m_jit.jump();
     4959
     4960            isNotString.link(&m_jit);
     4961            slowPath.append(m_jit.branchIfNotSymbol(keyRegs.payloadGPR()));
     4962            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), Symbol::offsetOfSymbolImpl()), implGPR);
     4963
     4964            hasUniquedImpl.link(&m_jit);
     4965            break;
     4966        }
     4967        default:
     4968            RELEASE_ASSERT_NOT_REACHED();
     4969        }
     4970
     4971        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
     4972        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
     4973        // ever load the result from the cache if the cache entry matches what we are querying for.
     4974        // So we either get super lucky and use zero for the hash and somehow collide with the entity
     4975        // we're looking for, or we realize we're comparing against another entity, and go to the
     4976        // slow path anyways.
     4977        m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
     4978        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
     4979        m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
     4980        m_jit.add32(structureIDGPR, hashGPR);
     4981        m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
     4982        m_jit.mul32(TrustedImm32(sizeof(HasOwnPropertyCache::Entry)), hashGPR, hashGPR);
     4983        ASSERT(m_jit.vm()->hasOwnPropertyCache());
     4984        m_jit.move(TrustedImmPtr(m_jit.vm()->hasOwnPropertyCache()), tempGPR);
     4985        slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual,
     4986            MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
     4987        m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
     4988        m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
     4989        slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
     4990        auto done = m_jit.jump();
     4991
     4992        slowPath.link(&m_jit);
     4993        silentSpillAllRegisters(resultGPR);
     4994        if (node->child2().useKind() != UntypedUse) {
     4995            m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), tempGPR);
     4996            keyRegs = JSValueRegs(tempGPR, keyRegs.payloadGPR());
     4997        }
     4998        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyRegs);
     4999        silentFillAllRegisters(resultGPR);
     5000        m_jit.exceptionCheck();
     5001
     5002        done.link(&m_jit);
     5003        booleanResult(resultGPR, node);
     5004#endif // CPU(X86)
     5005        break;
     5006    }
     5007
    48915008    case StoreBarrier: {
    48925009        compileStoreBarrier(node);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r206098 r206136  
    3737#include "DirectArguments.h"
    3838#include "GetterSetter.h"
     39#include "HasOwnPropertyCache.h"
    3940#include "JSCInlines.h"
    4041#include "JSEnvironmentRecord.h"
     
    46294630        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
    46304631        m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
    4631         m_jit.urshift64(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
     4632        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
    46324633        slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
    46334634        done.append(m_jit.jump());
     
    49364937        compileIn(node);
    49374938        break;
     4939
     4940    case HasOwnProperty: {
     4941        SpeculateCellOperand object(this, node->child1());
     4942        GPRTemporary uniquedStringImpl(this);
     4943        GPRTemporary temp(this);
     4944        GPRTemporary hash(this);
     4945        GPRTemporary structureID(this);
     4946        GPRTemporary result(this);
     4947
     4948        Optional<SpeculateCellOperand> keyAsCell;
     4949        Optional<JSValueOperand> keyAsValue;
     4950        GPRReg keyGPR;
     4951        if (node->child2().useKind() == UntypedUse) {
     4952            keyAsValue = JSValueOperand(this, node->child2());
     4953            keyGPR = keyAsValue->gpr();
     4954        } else {
     4955            ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == SymbolUse);
     4956            keyAsCell = SpeculateCellOperand(this, node->child2());
     4957            keyGPR = keyAsCell->gpr();
     4958        }
     4959
     4960        GPRReg objectGPR = object.gpr();
     4961        GPRReg implGPR = uniquedStringImpl.gpr();
     4962        GPRReg tempGPR = temp.gpr();
     4963        GPRReg hashGPR = hash.gpr();
     4964        GPRReg structureIDGPR = structureID.gpr();
     4965        GPRReg resultGPR = result.gpr();
     4966
     4967        speculateObject(node->child1());
     4968
     4969        MacroAssembler::JumpList slowPath;
     4970        switch (node->child2().useKind()) {
     4971        case SymbolUse: {
     4972            speculateSymbol(node->child2(), keyGPR);
     4973            m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
     4974            break;
     4975        }
     4976        case StringUse: {
     4977            speculateString(node->child2(), keyGPR);
     4978            m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
     4979            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
     4980            slowPath.append(m_jit.branchTest32(
     4981                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
     4982                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
     4983            break;
     4984        }
     4985        case UntypedUse: {
     4986            slowPath.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
     4987            auto isNotString = m_jit.branchIfNotString(keyGPR);
     4988            m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
     4989            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
     4990            slowPath.append(m_jit.branchTest32(
     4991                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
     4992                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
     4993            auto hasUniquedImpl = m_jit.jump();
     4994
     4995            isNotString.link(&m_jit);
     4996            slowPath.append(m_jit.branchIfNotSymbol(keyGPR));
     4997            m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
     4998
     4999            hasUniquedImpl.link(&m_jit);
     5000            break;
     5001        }
     5002        default:
     5003            RELEASE_ASSERT_NOT_REACHED();
     5004        }
     5005
     5006        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
     5007        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
     5008        // ever load the result from the cache if the cache entry matches what we are querying for.
     5009        // So we either get super lucky and use zero for the hash and somehow collide with the entity
     5010        // we're looking for, or we realize we're comparing against another entity, and go to the
     5011        // slow path anyways.
     5012        m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
     5013        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
     5014        m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
     5015        m_jit.add32(structureIDGPR, hashGPR);
     5016        m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
     5017        static_assert(sizeof(HasOwnPropertyCache::Entry) == 16, "Strong assumption of that here.");
     5018        m_jit.lshift32(TrustedImm32(4), hashGPR);
     5019        ASSERT(m_jit.vm()->hasOwnPropertyCache());
     5020        m_jit.move(TrustedImmPtr(m_jit.vm()->hasOwnPropertyCache()), tempGPR);
     5021        slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual,
     5022            MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
     5023        m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
     5024        m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
     5025        slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
     5026        auto done = m_jit.jump();
     5027
     5028        slowPath.link(&m_jit);
     5029        silentSpillAllRegisters(resultGPR);
     5030        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyGPR);
     5031        silentFillAllRegisters(resultGPR);
     5032        m_jit.exceptionCheck();
     5033
     5034        done.link(&m_jit);
     5035        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
     5036        jsValueResult(resultGPR, node, DataFormatJSBoolean);
     5037        break;
     5038    }
    49385039       
    49395040    case CountExecution:
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r204466 r206136  
    310310                    // https://bugs.webkit.org/show_bug.cgi?id=159602
    311311                    break;
     312                case HasOwnProperty: {
     313                    VALIDATE((node), !!m_graph.m_vm.hasOwnPropertyCache());
     314                    break;
     315                }
    312316                default:
    313317                    break;
  • trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h

    r205520 r206136  
    3232#include "DFGArrayMode.h"
    3333#include "FTLAbstractHeap.h"
     34#include "HasOwnPropertyCache.h"
    3435#include "IndexingType.h"
    3536#include "JSMap.h"
    3637#include "JSSet.h"
     38#include "Symbol.h"
    3739
    3840namespace JSC { namespace FTL {
     
    111113    macro(HashMapBucket_value, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()) \
    112114    macro(HashMapBucket_key, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()) \
     115    macro(Symbol_symbolImpl, Symbol::offsetOfSymbolImpl()) \
    113116
    114117#define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
     
    129132    macro(singleCharacterStrings, 0, sizeof(JSString*)) \
    130133    macro(structureTable, 0, sizeof(Structure*)) \
    131     macro(variables, 0, sizeof(Register))
     134    macro(variables, 0, sizeof(Register)) \
     135    macro(HasOwnPropertyCache, 0, sizeof(HasOwnPropertyCache::Entry)) \
    132136   
    133137#define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r206098 r206136  
    182182    case Unreachable:
    183183    case In:
     184    case HasOwnProperty:
    184185    case IsCellWithType:
    185186    case MapHash:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r206134 r206136  
    632632        case In:
    633633            compileIn();
     634            break;
     635        case HasOwnProperty:
     636            compileHasOwnProperty();
    634637            break;
    635638        case PutById:
     
    67716774
    67726775        setJSValue(vmCall(Int64, m_out.operation(operationGenericIn), m_callFrame, cell, lowJSValue(m_node->child1())));
     6776    }
     6777
     6778    void compileHasOwnProperty()
     6779    {
     6780        LBasicBlock slowCase = m_out.newBlock();
     6781        LBasicBlock continuation = m_out.newBlock();
     6782        LBasicBlock lastNext = nullptr;
     6783
     6784        LValue object = lowObject(m_node->child1());
     6785        LValue uniquedStringImpl;
     6786        LValue keyAsValue = nullptr;
     6787        switch (m_node->child2().useKind()) {
     6788        case StringUse: {
     6789            LBasicBlock isNonEmptyString = m_out.newBlock();
     6790            LBasicBlock isAtomicString = m_out.newBlock();
     6791
     6792            keyAsValue = lowString(m_node->child2());
     6793            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
     6794            m_out.branch(m_out.notNull(uniquedStringImpl), usually(isNonEmptyString), rarely(slowCase));
     6795
     6796            lastNext = m_out.appendTo(isNonEmptyString, isAtomicString);
     6797            LValue isNotAtomic = m_out.testIsZero32(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
     6798            m_out.branch(isNotAtomic, rarely(slowCase), usually(isAtomicString));
     6799
     6800            m_out.appendTo(isAtomicString, slowCase);
     6801            break;
     6802        }
     6803        case SymbolUse: {
     6804            keyAsValue = lowSymbol(m_node->child2());
     6805            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.Symbol_symbolImpl);
     6806            lastNext = m_out.insertNewBlocksBefore(slowCase);
     6807            break;
     6808        }
     6809        case UntypedUse: {
     6810            LBasicBlock isCellCase = m_out.newBlock();
     6811            LBasicBlock isStringCase = m_out.newBlock();
     6812            LBasicBlock notStringCase = m_out.newBlock();
     6813            LBasicBlock isNonEmptyString = m_out.newBlock();
     6814            LBasicBlock isSymbolCase = m_out.newBlock();
     6815            LBasicBlock hasUniquedStringImpl = m_out.newBlock();
     6816
     6817            keyAsValue = lowJSValue(m_node->child2());
     6818            m_out.branch(isCell(keyAsValue), usually(isCellCase), rarely(slowCase));
     6819
     6820            lastNext = m_out.appendTo(isCellCase, isStringCase);
     6821            m_out.branch(isString(keyAsValue), unsure(isStringCase), unsure(notStringCase));
     6822
     6823            m_out.appendTo(isStringCase, isNonEmptyString);
     6824            LValue implFromString = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
     6825            ValueFromBlock stringResult = m_out.anchor(implFromString);
     6826            m_out.branch(m_out.notNull(implFromString), usually(isNonEmptyString), rarely(slowCase));
     6827
     6828            m_out.appendTo(isNonEmptyString, notStringCase);
     6829            LValue isNotAtomic = m_out.testIsZero32(m_out.load32(implFromString, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
     6830            m_out.branch(isNotAtomic, rarely(slowCase), usually(hasUniquedStringImpl));
     6831
     6832            m_out.appendTo(notStringCase, isSymbolCase);
     6833            m_out.branch(isSymbol(keyAsValue), unsure(isSymbolCase), unsure(slowCase));
     6834
     6835            m_out.appendTo(isSymbolCase, hasUniquedStringImpl);
     6836            ValueFromBlock symbolResult = m_out.anchor(m_out.loadPtr(keyAsValue, m_heaps.Symbol_symbolImpl));
     6837            m_out.jump(hasUniquedStringImpl);
     6838
     6839            m_out.appendTo(hasUniquedStringImpl, slowCase);
     6840            uniquedStringImpl = m_out.phi(pointerType(), stringResult, symbolResult);
     6841            break;
     6842        }
     6843        default:
     6844            RELEASE_ASSERT_NOT_REACHED();
     6845        }
     6846
     6847        ASSERT(keyAsValue);
     6848
     6849        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
     6850        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
     6851        // ever load the result from the cache if the cache entry matches what we are querying for.
     6852        // So we either get super lucky and use zero for the hash and somehow collide with the entity
     6853        // we're looking for, or we realize we're comparing against another entity, and go to the
     6854        // slow path anyways.
     6855        LValue hash = m_out.lShr(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
     6856
     6857        LValue structureID = m_out.load32(object, m_heaps.JSCell_structureID);
     6858        LValue index = m_out.add(hash, structureID);
     6859        index = m_out.zeroExtPtr(m_out.bitAnd(index, m_out.constInt32(HasOwnPropertyCache::mask)));
     6860        ASSERT(vm().hasOwnPropertyCache());
     6861        LValue cache = m_out.constIntPtr(vm().hasOwnPropertyCache());
     6862
     6863        IndexedAbstractHeap& heap = m_heaps.HasOwnPropertyCache;
     6864        LValue sameStructureID = m_out.equal(structureID, m_out.load32(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfStructureID())));
     6865        LValue sameImpl = m_out.equal(uniquedStringImpl, m_out.loadPtr(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfImpl())));
     6866        ValueFromBlock fastResult = m_out.anchor(m_out.load8ZeroExt32(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfResult())));
     6867        LValue cacheHit = m_out.bitAnd(sameStructureID, sameImpl);
     6868
     6869        m_out.branch(m_out.notZero32(cacheHit), usually(continuation), rarely(slowCase));
     6870
     6871        m_out.appendTo(slowCase, continuation);
     6872        ValueFromBlock slowResult;
     6873        slowResult = m_out.anchor(vmCall(Int32, m_out.operation(operationHasOwnProperty), m_callFrame, object, keyAsValue));
     6874        m_out.jump(continuation);
     6875
     6876        m_out.appendTo(continuation, lastNext);
     6877        setBoolean(m_out.phi(Int32, fastResult, slowResult));
    67736878    }
    67746879
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r205850 r206136  
    3030#include "GCIncomingRefCountedSetInlines.h"
    3131#include "GCTypeMap.h"
     32#include "HasOwnPropertyCache.h"
    3233#include "HeapHelperPool.h"
    3334#include "HeapIterationScope.h"
     
    10231024        prepareForMarking();
    10241025        flushWriteBarrierBuffer();
     1026
     1027        if (HasOwnPropertyCache* cache = vm()->hasOwnPropertyCache())
     1028            cache->clear();
    10251029    }
    10261030
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r205675 r206136  
    222222typedef int32_t (JIT_OPERATION *Z_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
    223223typedef int32_t (JIT_OPERATION *Z_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
     224typedef int32_t (JIT_OPERATION *Z_JITOperation_EOI)(ExecState*, JSObject*, UniquedStringImpl*);
     225typedef int32_t (JIT_OPERATION *Z_JITOperation_EOJ)(ExecState*, JSObject*, EncodedJSValue);
    224226typedef size_t (JIT_OPERATION *S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
    225227typedef size_t (JIT_OPERATION *S_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r206104 r206136  
    6666    JSMapHasIntrinsic,
    6767    JSSetHasIntrinsic,
     68    HasOwnPropertyIntrinsic,
    6869
    6970    // Getter intrinsics.
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r205670 r206136  
    524524    bool hasPropertyGeneric(ExecState*, PropertyName, PropertySlot::InternalMethodType) const;
    525525    bool hasPropertyGeneric(ExecState*, unsigned propertyName, PropertySlot::InternalMethodType) const;
     526    bool hasOwnProperty(ExecState*, PropertyName, PropertySlot&) const;
    526527    bool hasOwnProperty(ExecState*, PropertyName) const;
    527528    bool hasOwnProperty(ExecState*, unsigned) const;
  • trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h

    r205753 r206136  
    200200// HasOwnProperty(O, P) from section 7.3.11 in the spec.
    201201// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty
    202 ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
    203 {
    204     PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
     202ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
     203{
     204    ASSERT(slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty);
    205205    if (LIKELY(const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot == JSObject::getOwnPropertySlot))
    206206        return JSObject::getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
     
    208208}
    209209
     210ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
     211{
     212    PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
     213    return hasOwnProperty(exec, propertyName, slot);
     214}
     215
    210216ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const
    211217{
  • trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp

    r205569 r206136  
    2424#include "Error.h"
    2525#include "GetterSetter.h"
     26#include "HasOwnPropertyCache.h"
    2627#include "JSFunction.h"
    2728#include "JSString.h"
     
    6162    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0);
    6263    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0);
    63     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1);
     64    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1, HasOwnPropertyIntrinsic);
    6465    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1);
    6566    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1);
     
    9899        return JSValue::encode(jsUndefined());
    99100    JSObject* thisObject = thisValue.toObject(exec);
    100     if (!thisObject)
     101    if (UNLIKELY(!thisObject))
    101102        return JSValue::encode(JSValue());
    102     return JSValue::encode(jsBoolean(thisObject->hasOwnProperty(exec, propertyName)));
     103
     104    Structure* structure = thisObject->structure(vm);
     105    HasOwnPropertyCache* hasOwnPropertyCache = vm.ensureHasOwnPropertyCache();
     106    if (Optional<bool> result = hasOwnPropertyCache->get(structure, propertyName)) {
     107        ASSERT(*result == thisObject->hasOwnProperty(exec, propertyName));
     108        ASSERT(!scope.exception());
     109        return JSValue::encode(jsBoolean(*result));
     110    }
     111
     112    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
     113    bool result = thisObject->hasOwnProperty(exec, propertyName, slot);
     114    if (UNLIKELY(scope.exception()))
     115        return JSValue::encode(jsUndefined());
     116
     117    hasOwnPropertyCache->tryAdd(vm, slot, thisObject, propertyName, result);
     118    return JSValue::encode(jsBoolean(result));
    103119}
    104120
  • trunk/Source/JavaScriptCore/runtime/Symbol.h

    r205335 r206136  
    6060    double toNumber(ExecState*) const;
    6161
     62    static ptrdiff_t offsetOfSymbolImpl()
     63    {
     64        // PrivateName is just a Ref<SymbolImpl> which can just be used as a SymbolImpl*.
     65        return OBJECT_OFFSETOF(Symbol, m_privateName);
     66    }
     67
    6268protected:
    6369    static void destroy(JSCell*);
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r205917 r206136  
    4848#include "GCActivityCallback.h"
    4949#include "GetterSetter.h"
     50#include "HasOwnPropertyCache.h"
    5051#include "Heap.h"
    5152#include "HeapIterationScope.h"
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r205989 r206136  
    9090class TypeProfiler;
    9191class TypeProfilerLog;
     92class HasOwnPropertyCache;
    9293class HeapProfiler;
    9394class Identifier;
     
    555556    ConcurrentJITLock m_regExpAllocatorLock;
    556557
     558    std::unique_ptr<HasOwnPropertyCache> m_hasOwnPropertyCache;
     559    ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.get(); }
     560    HasOwnPropertyCache* ensureHasOwnPropertyCache();
     561
    557562#if ENABLE(REGEXP_TRACING)
    558563    typedef ListHashSet<RegExp*> RTTraceList;
Note: See TracChangeset for help on using the changeset viewer.