⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 199069 in webkit


Ignore:
Timestamp:
Apr 5, 2016, 12:58:04 PM (11 years ago)
Author:
fpizlo@apple.com
Message:

PolymorphicAccess should have a MegamorphicLoad case
​https://bugs.webkit.org/show_bug.cgi?id=156182

Reviewed by Geoffrey Garen and Keith Miller.

Source/JavaScriptCore:

This introduces a new case to PolymorphicAccess called MegamorphicLoad. This inlines the lookup in
the PropertyTable. It's cheaper than switching on a huge number of cases and it's cheaper than
calling into C++ to do the same job - particularly since inlining the lookup into an access means
that we can precompute the hash code.

When writing the inline code for the hashtable lookup, I found that our hashing algorithm was not
optimal. It used a double-hashing method for reducing collision pathologies. This is great for
improving the performance of some worst-case scenarios. But this misses the point of a hashtable: we
want to optimize the average-case performance. When optimizing for average-case, we can choose to
either focus on maximizing the likelihood of the fast case happening, or to minimize the cost of the
worst-case, or to minimize the cost of the fast case. Even a very basic hashtable will achieve a high
probability of hitting the fast case. So, doing work to reduce the likelihood of a worst-case
pathology only makes sense if it also preserves the good performance of the fast case, or reduces the
likelihood of the worst-case by so much that it's a win for the average case even with a slow-down in
the fast case.

I don't believe, based on looking at how the double-hashing is implemented, that it's possible that
this preserves the good performance of the fast case. It requires at least one more value to be live
around the loop, and dramatically increases the register pressure at key points inside the loop. The
biggest offender is the doubleHash() method itself. There is no getting around how bad this is: if
the compiler live-range-splits that method to death to avoid degrading register pressure elsewhere
then we will pay a steep price anytime we take the second iteration around the loop; but if the
compiler doesn't split around the call then the hashtable lookup fast path will be full of spills on
some architectures (I performed biological register allocation and found that I needed 9 registers
for complete lookup, while x86-64 has only 6 callee-saves; OTOH ARM64 has 10 callee-saves so it might
be better off).

Hence, this patch changes the hashtable lookup to use simple linear probing. This was not a slow-down
on anything, and it made MegamorphicLoad much more sensible since it is less likely to have to spill.

There are some other small changes in this patch, like rationalizing the IC's choice between giving
up after a repatch (i.e. never trying again) and just pretending that nothing happened (so we can
try to repatch again in the future). It looked like the code in Repatch.cpp was set up to be able to
choose between those options, but we weren't fully taking advantage of it because the
regenerateWithCase() method just returned null for any failure, and didn't say whether it was the
sort of failure that renders the inline cache unrepatchable (like memory allocation failure). Now
this is all made explicit. I wanted to make sure this change happened in this patch since the
MegamorphicLoad code automagically generates a MegamorphicLoad case by coalescing other cases. Since
this is intended to avoid blowing out the cache and making it unrepatchable, I wanted to make sure
that the rules for giving up were something that made sense to me.

This is a big win on microbenchmarks. It's neutral on traditional JS benchmarks. It's a slight
speed-up for page loading, because many real websites like to have megamorphic property accesses.

  • bytecode/PolymorphicAccess.cpp:

(JSC::AccessGenerationResult::dump):
(JSC::AccessGenerationState::addWatchpoint):
(JSC::AccessCase::get):
(JSC::AccessCase::megamorphicLoad):
(JSC::AccessCase::replace):
(JSC::AccessCase::guardedByStructureCheck):
(JSC::AccessCase::couldStillSucceed):
(JSC::AccessCase::canBeReplacedByMegamorphicLoad):
(JSC::AccessCase::canReplace):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generate):
(JSC::PolymorphicAccess::PolymorphicAccess):
(JSC::PolymorphicAccess::~PolymorphicAccess):
(JSC::PolymorphicAccess::regenerateWithCases):
(JSC::PolymorphicAccess::regenerateWithCase):
(WTF::printInternal):

  • bytecode/PolymorphicAccess.h:

(JSC::AccessCase::isGet):
(JSC::AccessCase::isPut):
(JSC::AccessCase::isIn):
(JSC::AccessGenerationResult::AccessGenerationResult):
(JSC::AccessGenerationResult::operator==):
(JSC::AccessGenerationResult::operator!=):
(JSC::AccessGenerationResult::operator bool):
(JSC::AccessGenerationResult::kind):
(JSC::AccessGenerationResult::code):
(JSC::AccessGenerationResult::madeNoChanges):
(JSC::AccessGenerationResult::gaveUp):
(JSC::AccessGenerationResult::generatedNewCode):
(JSC::PolymorphicAccess::isEmpty):
(JSC::AccessGenerationState::AccessGenerationState):

  • bytecode/StructureStubInfo.cpp:

(JSC::StructureStubInfo::aboutToDie):
(JSC::StructureStubInfo::addAccessCase):

  • bytecode/StructureStubInfo.h:
  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
(JSC::AssemblyHelpers::loadProperty):
(JSC::emitRandomThunkImpl):
(JSC::AssemblyHelpers::emitRandomThunk):
(JSC::AssemblyHelpers::emitLoadStructure):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::loadValue):
(JSC::AssemblyHelpers::moveValueRegs):
(JSC::AssemblyHelpers::argumentsStart):
(JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
(JSC::AssemblyHelpers::emitLoadStructure): Deleted.

  • jit/GPRInfo.cpp:

(JSC::JSValueRegs::dump):

  • jit/GPRInfo.h:

(JSC::JSValueRegs::uses):

  • jit/Repatch.cpp:

(JSC::replaceWithJump):
(JSC::tryCacheGetByID):
(JSC::tryCachePutByID):
(JSC::tryRepatchIn):

  • jit/ThunkGenerators.cpp:

(JSC::virtualThunkFor):

  • runtime/Options.h:
  • runtime/PropertyMapHashTable.h:

(JSC::PropertyTable::begin):
(JSC::PropertyTable::find):
(JSC::PropertyTable::get):

  • runtime/Structure.h:

LayoutTests:

  • js/regress/megamorphic-load-expected.txt: Added.
  • js/regress/megamorphic-load.html: Added.
  • js/regress/script-tests/megamorphic-load.js: Added.
  • js/regress/string-repeat-not-resolving-no-inline-expected.txt: Added.
  • js/regress/string-repeat-not-resolving-no-inline.html: Added.
Location:
trunk
Files:
5 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r199064 r199069  
     12016-04-04  Filip Pizlo  <fpizlo@apple.com>
     2
     3        PolymorphicAccess should have a MegamorphicLoad case
     4        https://bugs.webkit.org/show_bug.cgi?id=156182
     5
     6        Reviewed by Geoffrey Garen and Keith Miller.
     7
     8        * js/regress/megamorphic-load-expected.txt: Added.
     9        * js/regress/megamorphic-load.html: Added.
     10        * js/regress/script-tests/megamorphic-load.js: Added.
     11        * js/regress/string-repeat-not-resolving-no-inline-expected.txt: Added.
     12        * js/regress/string-repeat-not-resolving-no-inline.html: Added.
     13
    1142016-04-05  Antti Koivisto  <antti@apple.com>
    215
  • trunk/Source/JavaScriptCore/ChangeLog

    r199062 r199069  
     12016-04-04  Filip Pizlo  <fpizlo@apple.com>
     2
     3        PolymorphicAccess should have a MegamorphicLoad case
     4        https://bugs.webkit.org/show_bug.cgi?id=156182
     5
     6        Reviewed by Geoffrey Garen and Keith Miller.
     7
     8        This introduces a new case to PolymorphicAccess called MegamorphicLoad. This inlines the lookup in
     9        the PropertyTable. It's cheaper than switching on a huge number of cases and it's cheaper than
     10        calling into C++ to do the same job - particularly since inlining the lookup into an access means
     11        that we can precompute the hash code.
     12
     13        When writing the inline code for the hashtable lookup, I found that our hashing algorithm was not
     14        optimal. It used a double-hashing method for reducing collision pathologies. This is great for
     15        improving the performance of some worst-case scenarios. But this misses the point of a hashtable: we
     16        want to optimize the average-case performance. When optimizing for average-case, we can choose to
     17        either focus on maximizing the likelihood of the fast case happening, or to minimize the cost of the
     18        worst-case, or to minimize the cost of the fast case. Even a very basic hashtable will achieve a high
     19        probability of hitting the fast case. So, doing work to reduce the likelihood of a worst-case
     20        pathology only makes sense if it also preserves the good performance of the fast case, or reduces the
     21        likelihood of the worst-case by so much that it's a win for the average case even with a slow-down in
     22        the fast case.
     23
     24        I don't believe, based on looking at how the double-hashing is implemented, that it's possible that
     25        this preserves the good performance of the fast case. It requires at least one more value to be live
     26        around the loop, and dramatically increases the register pressure at key points inside the loop. The
     27        biggest offender is the doubleHash() method itself. There is no getting around how bad this is: if
     28        the compiler live-range-splits that method to death to avoid degrading register pressure elsewhere
     29        then we will pay a steep price anytime we take the second iteration around the loop; but if the
     30        compiler doesn't split around the call then the hashtable lookup fast path will be full of spills on
     31        some architectures (I performed biological register allocation and found that I needed 9 registers
     32        for complete lookup, while x86-64 has only 6 callee-saves; OTOH ARM64 has 10 callee-saves so it might
     33        be better off).
     34
     35        Hence, this patch changes the hashtable lookup to use simple linear probing. This was not a slow-down
     36        on anything, and it made MegamorphicLoad much more sensible since it is less likely to have to spill.
     37
     38        There are some other small changes in this patch, like rationalizing the IC's choice between giving
     39        up after a repatch (i.e. never trying again) and just pretending that nothing happened (so we can
     40        try to repatch again in the future). It looked like the code in Repatch.cpp was set up to be able to
     41        choose between those options, but we weren't fully taking advantage of it because the
     42        regenerateWithCase() method just returned null for any failure, and didn't say whether it was the
     43        sort of failure that renders the inline cache unrepatchable (like memory allocation failure). Now
     44        this is all made explicit. I wanted to make sure this change happened in this patch since the
     45        MegamorphicLoad code automagically generates a MegamorphicLoad case by coalescing other cases. Since
     46        this is intended to avoid blowing out the cache and making it unrepatchable, I wanted to make sure
     47        that the rules for giving up were something that made sense to me.
     48       
     49        This is a big win on microbenchmarks. It's neutral on traditional JS benchmarks. It's a slight
     50        speed-up for page loading, because many real websites like to have megamorphic property accesses.
     51
     52        * bytecode/PolymorphicAccess.cpp:
     53        (JSC::AccessGenerationResult::dump):
     54        (JSC::AccessGenerationState::addWatchpoint):
     55        (JSC::AccessCase::get):
     56        (JSC::AccessCase::megamorphicLoad):
     57        (JSC::AccessCase::replace):
     58        (JSC::AccessCase::guardedByStructureCheck):
     59        (JSC::AccessCase::couldStillSucceed):
     60        (JSC::AccessCase::canBeReplacedByMegamorphicLoad):
     61        (JSC::AccessCase::canReplace):
     62        (JSC::AccessCase::generateWithGuard):
     63        (JSC::AccessCase::generate):
     64        (JSC::PolymorphicAccess::PolymorphicAccess):
     65        (JSC::PolymorphicAccess::~PolymorphicAccess):
     66        (JSC::PolymorphicAccess::regenerateWithCases):
     67        (JSC::PolymorphicAccess::regenerateWithCase):
     68        (WTF::printInternal):
     69        * bytecode/PolymorphicAccess.h:
     70        (JSC::AccessCase::isGet):
     71        (JSC::AccessCase::isPut):
     72        (JSC::AccessCase::isIn):
     73        (JSC::AccessGenerationResult::AccessGenerationResult):
     74        (JSC::AccessGenerationResult::operator==):
     75        (JSC::AccessGenerationResult::operator!=):
     76        (JSC::AccessGenerationResult::operator bool):
     77        (JSC::AccessGenerationResult::kind):
     78        (JSC::AccessGenerationResult::code):
     79        (JSC::AccessGenerationResult::madeNoChanges):
     80        (JSC::AccessGenerationResult::gaveUp):
     81        (JSC::AccessGenerationResult::generatedNewCode):
     82        (JSC::PolymorphicAccess::isEmpty):
     83        (JSC::AccessGenerationState::AccessGenerationState):
     84        * bytecode/StructureStubInfo.cpp:
     85        (JSC::StructureStubInfo::aboutToDie):
     86        (JSC::StructureStubInfo::addAccessCase):
     87        * bytecode/StructureStubInfo.h:
     88        * jit/AssemblyHelpers.cpp:
     89        (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
     90        (JSC::AssemblyHelpers::loadProperty):
     91        (JSC::emitRandomThunkImpl):
     92        (JSC::AssemblyHelpers::emitRandomThunk):
     93        (JSC::AssemblyHelpers::emitLoadStructure):
     94        * jit/AssemblyHelpers.h:
     95        (JSC::AssemblyHelpers::loadValue):
     96        (JSC::AssemblyHelpers::moveValueRegs):
     97        (JSC::AssemblyHelpers::argumentsStart):
     98        (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
     99        (JSC::AssemblyHelpers::emitLoadStructure): Deleted.
     100        * jit/GPRInfo.cpp:
     101        (JSC::JSValueRegs::dump):
     102        * jit/GPRInfo.h:
     103        (JSC::JSValueRegs::uses):
     104        * jit/Repatch.cpp:
     105        (JSC::replaceWithJump):
     106        (JSC::tryCacheGetByID):
     107        (JSC::tryCachePutByID):
     108        (JSC::tryRepatchIn):
     109        * jit/ThunkGenerators.cpp:
     110        (JSC::virtualThunkFor):
     111        * runtime/Options.h:
     112        * runtime/PropertyMapHashTable.h:
     113        (JSC::PropertyTable::begin):
     114        (JSC::PropertyTable::find):
     115        (JSC::PropertyTable::get):
     116        * runtime/Structure.h:
     117
    11182016-04-05  Antoine Quint  <graouts@apple.com>
    2119
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp

    r198212 r199069  
    11/*
    2  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    4747static const bool verbose = false;
    4848
     49void AccessGenerationResult::dump(PrintStream& out) const
     50{
     51    out.print(m_kind);
     52    if (m_code)
     53        out.print(":", m_code);
     54}
     55
    4956Watchpoint* AccessGenerationState::addWatchpoint(const ObjectPropertyCondition& condition)
    5057{
    … …  
    176183}
    177184
     185std::unique_ptr<AccessCase> AccessCase::megamorphicLoad(VM& vm, JSCell* owner)
     186{
     187    UNUSED_PARAM(vm);
     188    UNUSED_PARAM(owner);
     189   
     190    if (GPRInfo::numberOfRegisters < 9)
     191        return nullptr;
     192   
     193    std::unique_ptr<AccessCase> result(new AccessCase());
     194   
     195    result->m_type = MegamorphicLoad;
     196   
     197    return result;
     198}
     199
    178200std::unique_ptr<AccessCase> AccessCase::replace(
    179201    VM& vm, JSCell* owner, Structure* structure, PropertyOffset offset)
    … …  
    323345
    324346    switch (m_type) {
     347    case MegamorphicLoad:
    325348    case ArrayLength:
    326349    case StringLength:
    … …  
    343366}
    344367
    345 bool AccessCase::canReplace(const AccessCase& other)
     368bool AccessCase::canBeReplacedByMegamorphicLoad() const
     369{
     370    return type() == Load
     371        && !viaProxy()
     372        && conditionSet().isEmpty()
     373        && !additionalSet()
     374        && !customSlotBase();
     375}
     376
     377bool AccessCase::canReplace(const AccessCase& other) const
    346378{
    347379    // We could do a lot better here, but for now we just do something obvious.
     380   
     381    if (type() == MegamorphicLoad && other.canBeReplacedByMegamorphicLoad())
     382        return true;
    348383
    349384    if (!guardedByStructureCheck() || !other.guardedByStructureCheck()) {
    … …  
    408443{
    409444    CCallHelpers& jit = *state.jit;
     445    VM& vm = *jit.vm();
     446    const Identifier& ident = *state.ident;
     447    StructureStubInfo& stubInfo = *state.stubInfo;
     448    JSValueRegs valueRegs = state.valueRegs;
     449    GPRReg baseGPR = state.baseGPR;
     450    GPRReg scratchGPR = state.scratchGPR;
     451   
     452    UNUSED_PARAM(vm);
    410453
    411454    switch (m_type) {
    412455    case ArrayLength: {
    413456        ASSERT(!viaProxy());
    414         jit.load8(CCallHelpers::Address(state.baseGPR, JSCell::indexingTypeOffset()), state.scratchGPR);
     457        jit.load8(CCallHelpers::Address(baseGPR, JSCell::indexingTypeOffset()), scratchGPR);
    415458        fallThrough.append(
    416459            jit.branchTest32(
    417                 CCallHelpers::Zero, state.scratchGPR, CCallHelpers::TrustedImm32(IsArray)));
     460                CCallHelpers::Zero, scratchGPR, CCallHelpers::TrustedImm32(IsArray)));
    418461        fallThrough.append(
    419462            jit.branchTest32(
    420                 CCallHelpers::Zero, state.scratchGPR, CCallHelpers::TrustedImm32(IndexingShapeMask)));
     463                CCallHelpers::Zero, scratchGPR, CCallHelpers::TrustedImm32(IndexingShapeMask)));
    421464        break;
    422465    }
    … …  
    427470            jit.branch8(
    428471                CCallHelpers::NotEqual,
    429                 CCallHelpers::Address(state.baseGPR, JSCell::typeInfoTypeOffset()),
     472                CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()),
    430473                CCallHelpers::TrustedImm32(StringType)));
    431474        break;
     475    }
     476       
     477    case MegamorphicLoad: {
     478        UniquedStringImpl* key = ident.impl();
     479        unsigned hash = IdentifierRepHash::hash(key);
     480       
     481        ScratchRegisterAllocator allocator(stubInfo.patch.usedRegisters);
     482        allocator.lock(baseGPR);
     483#if USE(JSVALUE32_64)
     484        allocator.lock(static_cast<GPRReg>(stubInfo.patch.baseTagGPR));
     485#endif
     486        allocator.lock(valueRegs);
     487        allocator.lock(scratchGPR);
     488       
     489        GPRReg intermediateGPR = scratchGPR;
     490        GPRReg maskGPR = allocator.allocateScratchGPR();
     491        GPRReg maskedHashGPR = allocator.allocateScratchGPR();
     492        GPRReg indexGPR = allocator.allocateScratchGPR();
     493        GPRReg offsetGPR = allocator.allocateScratchGPR();
     494       
     495        if (verbose) {
     496            dataLog("baseGPR = ", baseGPR, "\n");
     497            dataLog("valueRegs = ", valueRegs, "\n");
     498            dataLog("scratchGPR = ", scratchGPR, "\n");
     499            dataLog("intermediateGPR = ", intermediateGPR, "\n");
     500            dataLog("maskGPR = ", maskGPR, "\n");
     501            dataLog("maskedHashGPR = ", maskedHashGPR, "\n");
     502            dataLog("indexGPR = ", indexGPR, "\n");
     503            dataLog("offsetGPR = ", offsetGPR, "\n");
     504        }
     505
     506        ScratchRegisterAllocator::PreservedState preservedState =
     507            allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
     508
     509        CCallHelpers::JumpList myFailAndIgnore;
     510        CCallHelpers::JumpList myFallThrough;
     511       
     512        jit.emitLoadStructure(baseGPR, intermediateGPR, maskGPR);
     513        jit.loadPtr(
     514            CCallHelpers::Address(intermediateGPR, Structure::propertyTableUnsafeOffset()),
     515            intermediateGPR);
     516       
     517        myFailAndIgnore.append(jit.branchTestPtr(CCallHelpers::Zero, intermediateGPR));
     518       
     519        jit.load32(CCallHelpers::Address(intermediateGPR, PropertyTable::offsetOfIndexMask()), maskGPR);
     520        jit.loadPtr(CCallHelpers::Address(intermediateGPR, PropertyTable::offsetOfIndex()), indexGPR);
     521        jit.load32(
     522            CCallHelpers::Address(intermediateGPR, PropertyTable::offsetOfIndexSize()),
     523            intermediateGPR);
     524
     525        jit.move(maskGPR, maskedHashGPR);
     526        jit.and32(CCallHelpers::TrustedImm32(hash), maskedHashGPR);
     527        jit.lshift32(CCallHelpers::TrustedImm32(2), intermediateGPR);
     528        jit.addPtr(indexGPR, intermediateGPR);
     529       
     530        CCallHelpers::Label loop = jit.label();
     531       
     532        jit.load32(CCallHelpers::BaseIndex(indexGPR, maskedHashGPR, CCallHelpers::TimesFour), offsetGPR);
     533       
     534        myFallThrough.append(
     535            jit.branch32(
     536                CCallHelpers::Equal,
     537                offsetGPR,
     538                CCallHelpers::TrustedImm32(PropertyTable::EmptyEntryIndex)));
     539       
     540        jit.sub32(CCallHelpers::TrustedImm32(1), offsetGPR);
     541        jit.mul32(CCallHelpers::TrustedImm32(sizeof(PropertyMapEntry)), offsetGPR, offsetGPR);
     542        jit.addPtr(intermediateGPR, offsetGPR);
     543       
     544        CCallHelpers::Jump collision =  jit.branchPtr(
     545            CCallHelpers::NotEqual,
     546            CCallHelpers::Address(offsetGPR, OBJECT_OFFSETOF(PropertyMapEntry, key)),
     547            CCallHelpers::TrustedImmPtr(key));
     548       
     549        // offsetGPR currently holds a pointer to the PropertyMapEntry, which has the offset and attributes.
     550        // Check them and then attempt the load.
     551       
     552        myFallThrough.append(
     553            jit.branchTest32(
     554                CCallHelpers::NonZero,
     555                CCallHelpers::Address(offsetGPR, OBJECT_OFFSETOF(PropertyMapEntry, attributes)),
     556                CCallHelpers::TrustedImm32(Accessor | CustomAccessor)));
     557       
     558        jit.load32(CCallHelpers::Address(offsetGPR, OBJECT_OFFSETOF(PropertyMapEntry, offset)), offsetGPR);
     559       
     560        jit.loadProperty(baseGPR, offsetGPR, valueRegs);
     561       
     562        allocator.restoreReusedRegistersByPopping(jit, preservedState);
     563        state.succeed();
     564       
     565        collision.link(&jit);
     566
     567        jit.add32(CCallHelpers::TrustedImm32(1), maskedHashGPR);
     568       
     569        // FIXME: We could be smarter about this. Currently we're burning a GPR for the mask. But looping
     570        // around isn't super common so we could, for example, recompute the mask from the difference between
     571        // the table and index. But before we do that we should probably make it easier to multiply and
     572        // divide by the size of PropertyMapEntry. That probably involves making PropertyMapEntry be arranged
     573        // to have a power-of-2 size.
     574        jit.and32(maskGPR, maskedHashGPR);
     575        jit.jump().linkTo(loop, &jit);
     576       
     577        if (allocator.didReuseRegisters()) {
     578            myFailAndIgnore.link(&jit);
     579            allocator.restoreReusedRegistersByPopping(jit, preservedState);
     580            state.failAndIgnore.append(jit.jump());
     581           
     582            myFallThrough.link(&jit);
     583            allocator.restoreReusedRegistersByPopping(jit, preservedState);
     584            fallThrough.append(jit.jump());
     585        } else {
     586            state.failAndIgnore.append(myFailAndIgnore);
     587            fallThrough.append(myFallThrough);
     588        }
     589        return;
    432590    }
    433591
    … …  
    437595                jit.branch8(
    438596                    CCallHelpers::NotEqual,
    439                     CCallHelpers::Address(state.baseGPR, JSCell::typeInfoTypeOffset()),
     597                    CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()),
    440598                    CCallHelpers::TrustedImm32(PureForwardingProxyType)));
    441599
    442             jit.loadPtr(
    443                 CCallHelpers::Address(state.baseGPR, JSProxy::targetOffset()),
    444                 state.scratchGPR);
     600            jit.loadPtr(CCallHelpers::Address(baseGPR, JSProxy::targetOffset()), scratchGPR);
    445601
    446602            fallThrough.append(
    447603                jit.branchStructure(
    448604                    CCallHelpers::NotEqual,
    449                     CCallHelpers::Address(state.scratchGPR, JSCell::structureIDOffset()),
     605                    CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()),
    450606                    structure()));
    451607        } else {
    … …  
    453609                jit.branchStructure(
    454610                    CCallHelpers::NotEqual,
    455                     CCallHelpers::Address(state.baseGPR, JSCell::structureIDOffset()),
     611                    CCallHelpers::Address(baseGPR, JSCell::structureIDOffset()),
    456612                    structure()));
    457613        }
    … …  
    10921248        emitIntrinsicGetter(state);
    10931249        return;
    1094     } }
     1250    }
     1251   
     1252    case MegamorphicLoad:
     1253        // These need to be handled by generateWithGuard(), since the guard is part of the megamorphic load
     1254        // algorithm. We can be sure that nobody will call generate() directly for MegamorphicLoad since
     1255        // MegamorphicLoad is not guarded by a structure check.
     1256        RELEASE_ASSERT_NOT_REACHED();
     1257    }
    10951258   
    10961259    RELEASE_ASSERT_NOT_REACHED();
    … …  
    11001263PolymorphicAccess::~PolymorphicAccess() { }
    11011264
    1102 MacroAssemblerCodePtr PolymorphicAccess::regenerateWithCases(
     1265AccessGenerationResult PolymorphicAccess::regenerateWithCases(
    11031266    VM& vm, CodeBlock* codeBlock, StructureStubInfo& stubInfo, const Identifier& ident,
    11041267    Vector<std::unique_ptr<AccessCase>> originalCasesToAdd)
    … …  
    11151278    //   add more things after failure.
    11161279   
    1117     // First, verify that we can generate code for all of the new cases while eliminating any of the
    1118     // new cases that replace each other.
     1280    // First ensure that the originalCasesToAdd doesn't contain duplicates.
    11191281    Vector<std::unique_ptr<AccessCase>> casesToAdd;
    11201282    for (unsigned i = 0; i < originalCasesToAdd.size(); ++i) {
    … …  
    11431305    // keep doing what they were doing before.
    11441306    if (casesToAdd.isEmpty())
    1145         return MacroAssemblerCodePtr();
     1307        return AccessGenerationResult::MadeNoChanges;
    11461308
    11471309    // Now construct the list of cases as they should appear if we are successful. This means putting
    … …  
    11721334    if (verbose)
    11731335        dataLog("newCases: ", listDump(newCases), "\n");
     1336   
     1337    // See if we are close to having too many cases and if some of those cases can be subsumed by a
     1338    // megamorphic load.
     1339    if (newCases.size() >= Options::maxAccessVariantListSize()) {
     1340        unsigned numSelfLoads = 0;
     1341        for (auto& newCase : newCases) {
     1342            if (newCase->canBeReplacedByMegamorphicLoad())
     1343                numSelfLoads++;
     1344        }
     1345       
     1346        if (numSelfLoads >= Options::megamorphicLoadCost()) {
     1347            if (auto mega = AccessCase::megamorphicLoad(vm, codeBlock)) {
     1348                newCases.removeAllMatching(
     1349                    [&] (std::unique_ptr<AccessCase>& newCase) -> bool {
     1350                        return newCase->canBeReplacedByMegamorphicLoad();
     1351                    });
     1352               
     1353                newCases.append(WTFMove(mega));
     1354            }
     1355        }
     1356    }
    11741357
    11751358    if (newCases.size() > Options::maxAccessVariantListSize()) {
    11761359        if (verbose)
    11771360            dataLog("Too many cases.\n");
    1178         return MacroAssemblerCodePtr();
     1361        return AccessGenerationResult::GaveUp;
    11791362    }
    11801363
    11811364    MacroAssemblerCodePtr result = regenerate(vm, codeBlock, stubInfo, ident, newCases);
    11821365    if (!result)
    1183         return MacroAssemblerCodePtr();
     1366        return AccessGenerationResult::GaveUp;
    11841367
    11851368    m_list = WTFMove(newCases);
    … …  
    11871370}
    11881371
    1189 MacroAssemblerCodePtr PolymorphicAccess::regenerateWithCase(
     1372AccessGenerationResult PolymorphicAccess::regenerateWithCase(
    11901373    VM& vm, CodeBlock* codeBlock, StructureStubInfo& stubInfo, const Identifier& ident,
    11911374    std::unique_ptr<AccessCase> newAccess)
    … …  
    14041587using namespace JSC;
    14051588
     1589void printInternal(PrintStream& out, AccessGenerationResult::Kind kind)
     1590{
     1591    switch (kind) {
     1592    case AccessGenerationResult::MadeNoChanges:
     1593        out.print("MadeNoChanges");
     1594        return;
     1595    case AccessGenerationResult::GaveUp:
     1596        out.print("GaveUp");
     1597        return;
     1598    case AccessGenerationResult::GeneratedNewCode:
     1599        out.print("GeneratedNewCode");
     1600        return;
     1601    }
     1602   
     1603    RELEASE_ASSERT_NOT_REACHED();
     1604}
     1605
    14061606void printInternal(PrintStream& out, AccessCase::AccessType type)
    14071607{
    … …  
    14101610        out.print("Load");
    14111611        return;
     1612    case AccessCase::MegamorphicLoad:
     1613        out.print("MegamorphicLoad");
     1614        return;
    14121615    case AccessCase::Transition:
    14131616        out.print("Transition");
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h

    r196331 r199069  
    11/*
    2  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    5454    enum AccessType {
    5555        Load,
     56        MegamorphicLoad,
    5657        Transition,
    5758        Replace,
    … …  
    8283            return false;
    8384        case Load:
     85        case MegamorphicLoad:
    8486        case Miss:
    8587        case Getter:
    … …  
    9799        switch (type) {
    98100        case Load:
     101        case MegamorphicLoad:
    99102        case Miss:
    100103        case Getter:
    … …  
    120123        switch (type) {
    121124        case Load:
     125        case MegamorphicLoad:
    122126        case Miss:
    123127        case Getter:
    … …  
    146150        PropertySlot::GetValueFunc = nullptr,
    147151        JSObject* customSlotBase = nullptr);
    148 
     152   
     153    static std::unique_ptr<AccessCase> megamorphicLoad(VM&, JSCell* owner);
     154   
    149155    static std::unique_ptr<AccessCase> replace(VM&, JSCell* owner, Structure*, PropertyOffset);
    150156
    … …  
    248254    // Is it still possible for this case to ever be taken?
    249255    bool couldStillSucceed() const;
    250 
     256   
    251257    static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
     258
     259    bool canBeReplacedByMegamorphicLoad() const;
    252260
    253261    // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
    254262    // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
    255263    // more useful, truth. This method can be conservative; it will return false when it doubt.
    256     bool canReplace(const AccessCase& other);
     264    bool canReplace(const AccessCase& other) const;
    257265
    258266    void dump(PrintStream& out) const;
    … …  
    309317};
    310318
     319class AccessGenerationResult {
     320public:
     321    enum Kind {
     322        MadeNoChanges,
     323        GaveUp,
     324        GeneratedNewCode
     325    };
     326   
     327    AccessGenerationResult()
     328    {
     329    }
     330   
     331    AccessGenerationResult(Kind kind)
     332        : m_kind(kind)
     333    {
     334        ASSERT(kind != GeneratedNewCode);
     335    }
     336   
     337    AccessGenerationResult(MacroAssemblerCodePtr code)
     338        : m_kind(GeneratedNewCode)
     339        , m_code(code)
     340    {
     341        RELEASE_ASSERT(code);
     342    }
     343   
     344    bool operator==(const AccessGenerationResult& other) const
     345    {
     346        return m_kind == other.m_kind && m_code == other.m_code;
     347    }
     348   
     349    bool operator!=(const AccessGenerationResult& other) const
     350    {
     351        return !(*this == other);
     352    }
     353   
     354    explicit operator bool() const
     355    {
     356        return *this != AccessGenerationResult();
     357    }
     358   
     359    Kind kind() const { return m_kind; }
     360   
     361    const MacroAssemblerCodePtr& code() const { return m_code; }
     362   
     363    bool madeNoChanges() const { return m_kind == MadeNoChanges; }
     364    bool gaveUp() const { return m_kind == GaveUp; }
     365    bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
     366   
     367    void dump(PrintStream&) const;
     368   
     369private:
     370    Kind m_kind;
     371    MacroAssemblerCodePtr m_code;
     372};
     373
    311374class PolymorphicAccess {
    312375    WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
    … …  
    319382    // pass a vector of non-null access cases. This will prune the access cases by rejecting any case
    320383    // in the list that is subsumed by a later case in the list.
    321     MacroAssemblerCodePtr regenerateWithCases(
     384    AccessGenerationResult regenerateWithCases(
    322385        VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>);
    323386
    324     MacroAssemblerCodePtr regenerateWithCase(
     387    AccessGenerationResult regenerateWithCase(
    325388        VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
    326389   
    … …  
    363426struct AccessGenerationState {
    364427    AccessGenerationState()
    365     : m_calculatedRegistersForCallAndExceptionHandling(false)
    366     , m_needsToRestoreRegistersIfException(false)
    367     , m_calculatedCallSiteIndex(false)
     428        : m_calculatedRegistersForCallAndExceptionHandling(false)
     429        , m_needsToRestoreRegistersIfException(false)
     430        , m_calculatedCallSiteIndex(false)
    368431    {
    369432    }
    … …  
    442505namespace WTF {
    443506
     507void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
    444508void printInternal(PrintStream&, JSC::AccessCase::AccessType);
    445509
  • trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp

    r195865 r199069  
    11/*
    2  * Copyright (C) 2008, 2014, 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2014-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    105105}
    106106
    107 MacroAssemblerCodePtr StructureStubInfo::addAccessCase(
     107AccessGenerationResult StructureStubInfo::addAccessCase(
    108108    CodeBlock* codeBlock, const Identifier& ident, std::unique_ptr<AccessCase> accessCase)
    109109{
    … …  
    111111   
    112112    if (!accessCase)
    113         return MacroAssemblerCodePtr();
     113        return AccessGenerationResult::MadeNoChanges;
    114114   
    115115    if (cacheType == CacheType::Stub)
    … …  
    127127    accessCases.append(WTFMove(accessCase));
    128128
    129     MacroAssemblerCodePtr result =
     129    AccessGenerationResult result =
    130130        access->regenerateWithCases(vm, codeBlock, *this, ident, WTFMove(accessCases));
    131131
    132     if (!result)
    133         return MacroAssemblerCodePtr();
     132    if (!result.generatedNewCode())
     133        return result;
    134134
    135135    initStub(codeBlock, WTFMove(access));
  • trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h

    r195865 r199069  
    11/*
    2  * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    3434#include "Opcode.h"
    3535#include "Options.h"
    36 #include "PolymorphicAccess.h"
    3736#include "RegisterSet.h"
    3837#include "Structure.h"
    … …  
    4342#if ENABLE(JIT)
    4443
     44class AccessCase;
     45class AccessGenerationResult;
    4546class PolymorphicAccess;
    4647
    … …  
    6970    void initStub(CodeBlock*, std::unique_ptr<PolymorphicAccess>);
    7071
    71     MacroAssemblerCodePtr addAccessCase(
    72         CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>);
     72    AccessGenerationResult addAccessCase(CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>);
    7373
    7474    void reset(CodeBlock*);
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp

    r198364 r199069  
    420420}
    421421
     422void AssemblyHelpers::loadProperty(GPRReg object, GPRReg offset, JSValueRegs result)
     423{
     424    Jump isInline = branch32(LessThan, offset, TrustedImm32(firstOutOfLineOffset));
     425   
     426    loadPtr(Address(object, JSObject::butterflyOffset()), result.payloadGPR());
     427    neg32(offset);
     428    signExtend32ToPtr(offset, offset);
     429    Jump ready = jump();
     430   
     431    isInline.link(this);
     432    addPtr(
     433        TrustedImm32(
     434            static_cast<int32_t>(sizeof(JSObject)) -
     435            (static_cast<int32_t>(firstOutOfLineOffset) - 2) * static_cast<int32_t>(sizeof(EncodedJSValue))),
     436        object, result.payloadGPR());
     437   
     438    ready.link(this);
     439   
     440    loadValue(
     441        BaseIndex(
     442            result.payloadGPR(), offset, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)),
     443        result);
     444}
     445
     446void AssemblyHelpers::emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
     447{
     448#if USE(JSVALUE64)
     449    load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
     450    loadPtr(vm()->heap.structureIDTable().base(), scratch);
     451    loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
     452#else
     453    UNUSED_PARAM(scratch);
     454    loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
     455#endif
     456}
     457
    422458#if USE(JSVALUE64)
    423459template<typename LoadFromHigh, typename StoreToHigh, typename LoadFromLow, typename StoreToLow>
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r198364 r199069  
    150150#endif
    151151    }
     152   
     153    // Note that this clobbers offset.
     154    void loadProperty(GPRReg object, GPRReg offset, JSValueRegs result);
    152155
    153156    void moveValueRegs(JSValueRegs srcRegs, JSValueRegs destRegs)
    … …  
    12101213    }
    12111214   
    1212     void emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
    1213     {
    1214 #if USE(JSVALUE64)
    1215         load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
    1216         loadPtr(vm()->heap.structureIDTable().base(), scratch);
    1217         loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
    1218 #else
    1219         UNUSED_PARAM(scratch);
    1220         loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
    1221 #endif
    1222     }
    1223 
    1224     static void emitLoadStructure(AssemblyHelpers& jit, RegisterID base, RegisterID dest, RegisterID scratch)
    1225     {
    1226 #if USE(JSVALUE64)
    1227         jit.load32(MacroAssembler::Address(base, JSCell::structureIDOffset()), dest);
    1228         jit.loadPtr(jit.vm()->heap.structureIDTable().base(), scratch);
    1229         jit.loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
    1230 #else
    1231         UNUSED_PARAM(scratch);
    1232         jit.loadPtr(MacroAssembler::Address(base, JSCell::structureIDOffset()), dest);
    1233 #endif
    1234     }
     1215    void emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch);
    12351216
    12361217    void emitStoreStructureWithTypeInfo(TrustedImmPtr structure, RegisterID dest, RegisterID)
  • trunk/Source/JavaScriptCore/jit/GPRInfo.cpp

    r194894 r199069  
    3131namespace JSC {
    3232
     33void JSValueRegs::dump(PrintStream& out) const
     34{
     35#if USE(JSVALUE64)
     36    out.print(m_gpr);
     37#else
     38    out.print("(tag:", tagGPR(), ", payload:", payloadGPR(), ")");
     39#endif
     40}
     41
    3342// This is in the .cpp file to work around clang issues.
    3443#if CPU(X86_64)
  • trunk/Source/JavaScriptCore/jit/GPRInfo.h

    r195182 r199069  
    7878    bool uses(GPRReg gpr) const { return m_gpr == gpr; }
    7979   
     80    void dump(PrintStream&) const;
     81   
    8082private:
    8183    GPRReg m_gpr;
    … …  
    202204
    203205    bool uses(GPRReg gpr) const { return m_tagGPR == gpr || m_payloadGPR == gpr; }
     206   
     207    void dump(PrintStream&) const;
    204208   
    205209private:
  • trunk/Source/JavaScriptCore/jit/Repatch.cpp

    r196331 r199069  
    11/*
    2  * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    162162static void replaceWithJump(StructureStubInfo& stubInfo, const MacroAssemblerCodePtr target)
    163163{
     164    RELEASE_ASSERT(target);
     165   
    164166    if (MacroAssembler::canJumpReplacePatchableBranch32WithPatch()) {
    165167        MacroAssembler::replaceWithJump(
    … …  
    316318    }
    317319
    318     MacroAssemblerCodePtr codePtr =
    319         stubInfo.addAccessCase(codeBlock, propertyName, WTFMove(newCase));
    320 
    321     if (!codePtr)
    322         return GiveUpOnCache;
    323 
    324     replaceWithJump(stubInfo, codePtr);
     320    AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, propertyName, WTFMove(newCase));
     321
     322    if (result.gaveUp())
     323        return GiveUpOnCache;
     324    if (result.madeNoChanges())
     325        return RetryCacheLater;
     326   
     327    RELEASE_ASSERT(result.code());
     328    replaceWithJump(stubInfo, result.code());
    325329   
    326330    return RetryCacheLater;
    … …  
    458462    }
    459463
    460     MacroAssemblerCodePtr codePtr = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
    461    
    462     if (!codePtr)
    463         return GiveUpOnCache;
    464 
     464    AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
     465   
     466    if (result.gaveUp())
     467        return GiveUpOnCache;
     468    if (result.madeNoChanges())
     469        return RetryCacheLater;
     470
     471    RELEASE_ASSERT(result.code());
    465472    resetPutByIDCheckAndLoad(stubInfo);
    466473    MacroAssembler::repatchJump(
    467474        stubInfo.callReturnLocation.jumpAtOffset(
    468475            stubInfo.patch.deltaCallToJump),
    469         CodeLocationLabel(codePtr));
     476        CodeLocationLabel(result.code()));
    470477   
    471478    return RetryCacheLater;
    … …  
    515522        vm, codeBlock, wasFound ? AccessCase::InHit : AccessCase::InMiss, structure, conditionSet);
    516523
    517     MacroAssemblerCodePtr codePtr = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
    518     if (!codePtr)
    519         return GiveUpOnCache;
    520 
     524    AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
     525    if (result.gaveUp())
     526        return GiveUpOnCache;
     527    if (result.madeNoChanges())
     528        return RetryCacheLater;
     529
     530    RELEASE_ASSERT(result.code());
    521531    MacroAssembler::repatchJump(
    522532        stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump),
    523         CodeLocationLabel(codePtr));
     533        CodeLocationLabel(result.code()));
    524534   
    525535    return RetryCacheLater;
  • trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp

    r198981 r199069  
    192192            CCallHelpers::TrustedImm32(JSValue::CellTag)));
    193193#endif
    194     AssemblyHelpers::emitLoadStructure(jit, GPRInfo::regT0, GPRInfo::regT4, GPRInfo::regT1);
     194    jit.emitLoadStructure(GPRInfo::regT0, GPRInfo::regT4, GPRInfo::regT1);
    195195    slowCase.append(
    196196        jit.branchPtr(
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r198975 r199069  
    188188    v(bool, clobberAllRegsInFTLICSlowPath, !ASSERT_DISABLED, nullptr) \
    189189    v(bool, useAccessInlining, true, nullptr) \
    190     v(unsigned, maxAccessVariantListSize, 8, nullptr) \
     190    v(unsigned, maxAccessVariantListSize, 13, nullptr) \
     191    v(unsigned, megamorphicLoadCost, 10, nullptr) \
    191192    v(bool, usePolyvariantDevirtualization, true, nullptr) \
    192193    v(bool, usePolymorphicAccessInlining, true, nullptr) \
  • trunk/Source/JavaScriptCore/runtime/PropertyMapHashTable.h

    r184828 r199069  
    192192    void checkConsistency();
    193193#endif
     194   
     195    static ptrdiff_t offsetOfIndexSize() { return OBJECT_OFFSETOF(PropertyTable, m_indexSize); }
     196    static ptrdiff_t offsetOfIndexMask() { return OBJECT_OFFSETOF(PropertyTable, m_indexMask); }
     197    static ptrdiff_t offsetOfIndex() { return OBJECT_OFFSETOF(PropertyTable, m_index); }
     198
     199    static const unsigned EmptyEntryIndex = 0;
    194200
    195201private:
    … …  
    245251
    246252    static const unsigned MinimumTableSize = 16;
    247     static const unsigned EmptyEntryIndex = 0;
    248253};
    249254
    … …  
    273278    ASSERT(key->isAtomic() || key->isSymbol());
    274279    unsigned hash = IdentifierRepHash::hash(key);
    275     unsigned step = 0;
    276280
    277281#if DUMP_PROPERTYMAP_STATS
    … …  
    286290            return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
    287291
    288         if (!step)
    289             step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
    290 
    291292#if DUMP_PROPERTYMAP_STATS
    292293        ++propertyMapHashTableStats->numCollisions;
    … …  
    294295
    295296#if DUMP_PROPERTYMAP_COLLISIONS
    296         dataLog("PropertyTable collision for ", key, " (", hash, ") with step ", step, "\n");
     297        dataLog("PropertyTable collision for ", key, " (", hash, ")\n");
    297298        dataLog("Collided with ", table()[entryIndex - 1].key, "(", IdentifierRepHash::hash(table()[entryIndex - 1].key), ")\n");
    298299#endif
    299300
    300         hash += step;
     301        hash++;
    301302    }
    302303}
    … …  
    311312
    312313    unsigned hash = IdentifierRepHash::hash(key);
    313     unsigned step = 0;
    314314
    315315#if DUMP_PROPERTYMAP_STATS
    … …  
    328328#endif
    329329
    330         if (!step)
    331             step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
    332         hash += step;
     330        hash++;
    333331    }
    334332}
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r197712 r199069  
    421421        return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset();
    422422    }
     423   
     424    static ptrdiff_t propertyTableUnsafeOffset()
     425    {
     426        return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
     427    }
    423428
    424429    static Structure* createStructure(VM&);
Note: See TracChangeset for help on using the changeset viewer.