Ignore:
Timestamp:
Aug 12, 2020, 9:50:12 PM (5 years ago)
Author:
[email protected]
Message:

Inline cache Replace and Setters on PureForwardingProxy
https://bugs.webkit.org/show_bug.cgi?id=215250

Reviewed by Yusuke Suzuki.

JSTests:

  • microbenchmarks/property-replace-and-setter-on-js-proxy.js: Added.

(assert):
(foo):

Source/JavaScriptCore:

We didn't used to cache any Puts on PureForwardingProxy. This patch
implements Replace and JS/Custom Setters on PureForwardingProxy. We don't support
Transition puts because in our current implementation different global objects
will never share the same structure.

This patch also aligns how our runtime and the ICs invoke Customs when the
passed in |this| value is a JSProxy. For custom accessors, our runtime passes
in the JSProxy, where our ICs used to pass in the target of the JSProxy, for
the receiver value. For custom values, the IC behavior and the runtime were
already aligned in passing in the property owner, which is the JSProxy's
target. This patch aligns our IC behavior to match our runtime behavior.

This patch also renames some of the registers in the IC code to clear
up what they're used for.

This is a 2.5x speedup on the microbenchmark I've added, and a 15-20% speedup
on JetStream2's 3d-cube-SP.

  • bytecode/AccessCase.cpp:

(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):

  • bytecode/GetterSetterAccessCase.cpp:

(JSC::GetterSetterAccessCase::create):

  • bytecode/GetterSetterAccessCase.h:
  • jit/JITOperations.cpp:
  • jit/Repatch.cpp:

(JSC::tryCachePutByID):

  • runtime/CommonSlowPaths.h:

(JSC::CommonSlowPaths::originalStructureBeforePut):
(JSC::CommonSlowPaths::putDirectWithReify):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/Repatch.cpp

    r265000 r265600  
    592592            return GiveUpOnCache;
    593593
     594        JSCell* baseCell = baseValue.asCell();
     595
     596        bool isProxy = false;
     597        if (baseCell->type() == PureForwardingProxyType) {
     598            baseCell = jsCast<JSProxy*>(baseCell)->target();
     599            baseValue = baseCell;
     600            isProxy = true;
     601
     602            // We currently only cache Replace and JS/Custom Setters on JSProxy. We don't
     603            // cache transitions because global objects will never share the same structure
     604            // in our current implementation.
     605            bool isCacheableProxy = (slot.isCacheablePut() && slot.type() == PutPropertySlot::ExistingProperty)
     606                || slot.isCacheableSetter()
     607                || slot.isCacheableCustom();
     608            if (!isCacheableProxy)
     609                return GiveUpOnCache;
     610        }
     611
    594612        std::unique_ptr<AccessCase> newCase;
    595         JSCell* baseCell = baseValue.asCell();
    596613
    597614        if (slot.base() == baseValue && slot.isCacheablePut()) {
     
    609626                if (stubInfo.cacheType() == CacheType::Unset
    610627                    && InlineAccess::canGenerateSelfPropertyReplace(stubInfo, slot.cachedOffset())
    611                     && !oldStructure->needImpurePropertyWatchpoint()) {
     628                    && !oldStructure->needImpurePropertyWatchpoint()
     629                    && !isProxy) {
    612630                   
    613631                    bool generatedCodeInline = InlineAccess::generateSelfPropertyReplace(stubInfo, oldStructure, slot.cachedOffset());
     
    620638                }
    621639
    622                 newCase = AccessCase::create(vm, codeBlock, AccessCase::Replace, propertyName, slot.cachedOffset(), oldStructure);
     640                newCase = ProxyableAccessCase::create(vm, codeBlock, AccessCase::Replace, propertyName, slot.cachedOffset(), oldStructure, ObjectPropertyConditionSet(), isProxy);
    623641            } else {
     642                ASSERT(!isProxy);
    624643                ASSERT(slot.type() == PutPropertySlot::NewProperty);
    625644
     
    707726                newCase = GetterSetterAccessCase::create(
    708727                    vm, codeBlock, slot.isCustomAccessor() ? AccessCase::CustomAccessorSetter : AccessCase::CustomValueSetter, oldStructure, propertyName,
    709                     invalidOffset, conditionSet, WTFMove(prototypeAccessChain), slot.customSetter(), slot.base() != baseValue ? slot.base() : nullptr);
     728                    invalidOffset, conditionSet, WTFMove(prototypeAccessChain), isProxy, slot.customSetter(), slot.base() != baseValue ? slot.base() : nullptr);
    710729            } else {
     730                ASSERT(slot.isCacheableSetter());
    711731                ObjectPropertyConditionSet conditionSet;
    712732                std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain;
     
    743763
    744764                newCase = GetterSetterAccessCase::create(
    745                     vm, codeBlock, AccessCase::Setter, oldStructure, propertyName, offset, conditionSet, WTFMove(prototypeAccessChain));
     765                    vm, codeBlock, AccessCase::Setter, oldStructure, propertyName, offset, conditionSet, WTFMove(prototypeAccessChain), isProxy);
    746766            }
    747767        }
Note: See TracChangeset for help on using the changeset viewer.