Skip to content
Permalink
Browse files
[JSC] Add ProxyObjectLoad IC
https://bugs.webkit.org/show_bug.cgi?id=244362

Reviewed by Justin Michaud.

This patch adds optimization for Proxy's [[Get]].

1. This patch adds ProxyObjectLoad IC, which detects ProxyObject and calls @performProxyObjectGet JS function. This handles
   property lookup in handler / target significantly faster. And we can jump to ProxyObject [[Get]] path instead of going to
   C++ and going back to JS.
2. This patch adds GetByValWithThis IC, it means we thisGPR register handling is added to GetByVal IC too. And we start using
   it in Baseline, DFG, and FTL. This IC is added since @performProxyObjectGet needs this operation in a super faster way.

Still, we have a lot of good optimization: DFG layer conversion from GetByValWithThis to GetByIdWithThis. Handling ProxyObjectLoad
in DFG and inline @performProxyObjectGet. But for now, let's just do optimization via IC since it can make baseline speed faster
in all JIT tiers.

This improves Proxy [[Get]] significantly in microbenchmarks. And we observed 8% improvement in JetStream2 chai-wtb since it heavily uses Proxy.

                                       ToT                     Patched

    proxy-get                   608.4166+-0.6237     ^    147.8951+-1.1855        ^ definitely 4.1138x faster
    proxy-get-miss-handler      304.8690+-0.8261     ^     48.4809+-0.1115        ^ definitely 6.2884x faster

* JSTests/microbenchmarks/proxy-get-miss-handler.js: Added.
* JSTests/microbenchmarks/proxy-get.js: Added.
(get target):
* Source/JavaScriptCore/CMakeLists.txt:
* Source/JavaScriptCore/DerivedSources-input.xcfilelist:
* Source/JavaScriptCore/DerivedSources.make:
* Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj:
* Source/JavaScriptCore/Sources.txt:
* Source/JavaScriptCore/builtins/BuiltinNames.h:
* Source/JavaScriptCore/builtins/ProxyHelpers.js: Added.
(linkTimeConstant.performProxyObjectGet):
* Source/JavaScriptCore/bytecode/AccessCase.cpp:
(JSC::AccessCase::create):
(JSC::AccessCase::guardedByStructureCheckSkippingConstantIdentifierCheck const):
(JSC::AccessCase::requiresIdentifierNameMatch const):
(JSC::AccessCase::requiresInt32PropertyCheck const):
(JSC::AccessCase::needsScratchFPR const):
(JSC::AccessCase::forEachDependentCell const):
(JSC::AccessCase::doesCalls const):
(JSC::AccessCase::canReplace const):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):
(JSC::AccessCase::canBeShared):
* Source/JavaScriptCore/bytecode/AccessCase.h:
(JSC::SharedJITStubSet::Hash::Key::Key):
(JSC::SharedJITStubSet::Hash::Key::operator==):
(JSC::SharedJITStubSet::Searcher::Translator::equal):
* Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h:
* Source/JavaScriptCore/bytecode/BytecodeList.rb:
* Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp:
(JSC::GetterSetterAccessCase::emitDOMJITGetter):
* Source/JavaScriptCore/bytecode/LinkTimeConstant.h:
* Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.cpp:
(JSC::ModuleNamespaceAccessCase::emit):
* Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationState::makeDefaultScratchAllocator):
(JSC::PolymorphicAccess::regenerate):
(WTF::printInternal):
* Source/JavaScriptCore/bytecode/PolymorphicAccess.h:
(JSC::AccessGenerationState::thisGPR const): Deleted.
(JSC::AccessGenerationState::prototypeGPR const): Deleted.
(JSC::AccessGenerationState::propertyGPR const): Deleted.
* Source/JavaScriptCore/bytecode/ProxyObjectAccessCase.cpp: Added.
(JSC::ProxyObjectAccessCase::ProxyObjectAccessCase):
(JSC::ProxyObjectAccessCase::create):
(JSC::ProxyObjectAccessCase::clone const):
(JSC::ProxyObjectAccessCase::emit):
(JSC::ProxyObjectAccessCase::dumpImpl const):
* Source/JavaScriptCore/bytecode/ProxyObjectAccessCase.h: Added.
* Source/JavaScriptCore/bytecode/Repatch.cpp:
(JSC::appropriateOptimizingGetByFunction):
(JSC::appropriateGetByFunction):
(JSC::tryCacheGetBy):
(JSC::resetGetBy):
* Source/JavaScriptCore/bytecode/Repatch.h:
* Source/JavaScriptCore/bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::reset):
(JSC::slowOperationFromUnlinkedStructureStubInfo):
(JSC::StructureStubInfo::initializeFromUnlinkedStructureStubInfo):
(JSC::StructureStubInfo::initializeFromDFGUnlinkedStructureStubInfo):
(JSC::StructureStubInfo::checkConsistency):
* Source/JavaScriptCore/bytecode/StructureStubInfo.h:
(JSC::StructureStubInfo::thisValueIsInExtraGPR const):
(JSC::StructureStubInfo::prototypeGPR const):
(JSC::StructureStubInfo::propertyGPR const):
(JSC::StructureStubInfo::propertyTagGPR const):
* Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:
(JSC::BytecodeIntrinsicNode::emit_intrinsic_getByValWithThis):
* Source/JavaScriptCore/dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* Source/JavaScriptCore/dfg/DFGJITCode.h:
* Source/JavaScriptCore/dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* Source/JavaScriptCore/dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addGetByValWithThis):
* Source/JavaScriptCore/dfg/DFGOperations.cpp:
* Source/JavaScriptCore/dfg/DFGOperations.h:
* Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp:
* Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileGetByValWithThis):
* Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileGetByValWithThis):
* Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetByValWithThis):
* Source/JavaScriptCore/jit/BaselineJITRegisters.h:
* Source/JavaScriptCore/jit/ICStats.h:
* Source/JavaScriptCore/jit/IntrinsicEmitter.cpp:
(JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
* Source/JavaScriptCore/jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::link):
* Source/JavaScriptCore/jit/JIT.h:
* Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp:
(JSC::JITGetByValGenerator::finalize):
(JSC::JITGetByValWithThisGenerator::JITGetByValWithThisGenerator):
(JSC::JITGetByValWithThisGenerator::generateFastPath):
(JSC::JITGetByValWithThisGenerator::generateEmptyPath):
(JSC::JITGetByValWithThisGenerator::finalize):
* Source/JavaScriptCore/jit/JITInlineCacheGenerator.h:
(JSC::JITInlineCacheGenerator::JITInlineCacheGenerator): Deleted.
(JSC::JITByIdGenerator::JITByIdGenerator): Deleted.
(JSC::JITInByValGenerator::JITInByValGenerator): Deleted.
* Source/JavaScriptCore/jit/JITOperations.cpp:
(JSC::getByValWithThis):
(JSC::JSC_DEFINE_JIT_OPERATION):
* Source/JavaScriptCore/jit/JITOperations.h:
* Source/JavaScriptCore/jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val_with_this):
(JSC::JIT::emitSlow_op_get_by_val_with_this):
(JSC::JIT::slow_op_get_by_val_with_this_callSlowOperationThenCheckExceptionGenerator):
* Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:
(JSC::JSC_DEFINE_COMMON_SLOW_PATH):
* Source/JavaScriptCore/runtime/JSGlobalObject.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
(JSC::JSGlobalObject::init):
* Source/JavaScriptCore/runtime/Operations.h:
(JSC::getByValWithIndexAndThis):
* Source/JavaScriptCore/runtime/ProxyObject.h:

Canonical link: https://commits.webkit.org/254092@main
  • Loading branch information
Constellation committed Sep 2, 2022
1 parent de802e0 commit a328f5aa59d892239b1bb119de0bfeb7169cc4f8
Show file tree
Hide file tree
Showing 50 changed files with 1,204 additions and 179 deletions.
@@ -0,0 +1,4 @@
var proxy = new Proxy({}, {});

for (var i = 0; i < 1e7; ++i)
proxy.test;
@@ -0,0 +1,8 @@
var proxy = new Proxy({}, {
get(target, propertyName, receiver) {
return 42;
}
});

for (var i = 0; i < 1e7; ++i)
proxy.test;
@@ -0,0 +1,19 @@
function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error('bad value: ' + actual);
}

let target = {};
let handlers = {
get(target, property, receiver) {
shouldBe(target, target);
shouldBe(receiver, p);
shouldBe(property, Symbol.iterator);
shouldBe(this, handlers);
return 42;
}
};
let p = new Proxy(target, handlers);

for (var i = 0; i < 1e4; ++i)
shouldBe(p[Symbol.iterator], 42);
@@ -355,6 +355,7 @@ set(JavaScriptCore_BUILTINS_SOURCES
${JAVASCRIPTCORE_DIR}/builtins/PromiseConstructor.js
${JAVASCRIPTCORE_DIR}/builtins/PromiseOperations.js
${JAVASCRIPTCORE_DIR}/builtins/PromisePrototype.js
${JAVASCRIPTCORE_DIR}/builtins/ProxyHelpers.js
${JAVASCRIPTCORE_DIR}/builtins/ReflectObject.js
${JAVASCRIPTCORE_DIR}/builtins/RegExpPrototype.js
${JAVASCRIPTCORE_DIR}/builtins/RegExpStringIteratorPrototype.js
@@ -59,6 +59,7 @@ $(PROJECT_DIR)/builtins/ObjectConstructor.js
$(PROJECT_DIR)/builtins/PromiseConstructor.js
$(PROJECT_DIR)/builtins/PromiseOperations.js
$(PROJECT_DIR)/builtins/PromisePrototype.js
$(PROJECT_DIR)/builtins/ProxyHelpers.js
$(PROJECT_DIR)/builtins/ReflectObject.js
$(PROJECT_DIR)/builtins/RegExpPrototype.js
$(PROJECT_DIR)/builtins/RegExpStringIteratorPrototype.js
@@ -126,6 +126,7 @@ JavaScriptCore_BUILTINS_SOURCES = \
$(JavaScriptCore)/builtins/PromiseConstructor.js \
$(JavaScriptCore)/builtins/PromiseOperations.js \
$(JavaScriptCore)/builtins/PromisePrototype.js \
$(JavaScriptCore)/builtins/ProxyHelpers.js \
$(JavaScriptCore)/builtins/ReflectObject.js \
$(JavaScriptCore)/builtins/RegExpPrototype.js \
${JavaScriptCore}/builtins/RegExpStringIteratorPrototype.js \
@@ -1854,6 +1854,7 @@
E307178D24C7829A00DF0644 /* IntlLocaleConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A3AFF92C245A3CFA00C9BA3B /* IntlLocaleConstructor.h */; };
E307178E24C7829D00DF0644 /* IntlLocale.h in Headers */ = {isa = PBXBuildFile; fileRef = A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */; };
E30873E7272559410053B601 /* IntlPluralRules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7D5FB18F20744BF1005DDF64 /* IntlPluralRules.cpp */; };
E30D903A28B77F28008B2CDC /* ProxyObjectAccessCase.h in Headers */ = {isa = PBXBuildFile; fileRef = E30D903828B77F28008B2CDC /* ProxyObjectAccessCase.h */; };
E30E8A5426DE2E4800DA4915 /* TemporalTimeZonePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E30E8A4E26DE2E4700DA4915 /* TemporalTimeZonePrototype.h */; };
E30E8A5626DE2E4800DA4915 /* TemporalTimeZone.h in Headers */ = {isa = PBXBuildFile; fileRef = E30E8A5026DE2E4800DA4915 /* TemporalTimeZone.h */; };
E30E8A5726DE2E4800DA4915 /* TemporalTimeZoneConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = E30E8A5126DE2E4800DA4915 /* TemporalTimeZoneConstructor.h */; };
@@ -5283,6 +5284,8 @@
E307178024C7824700DF0644 /* IntlSegmenter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IntlSegmenter.cpp; sourceTree = "<group>"; };
E307178124C7824700DF0644 /* IntlSegmenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntlSegmenter.h; sourceTree = "<group>"; };
E307178224C7824700DF0644 /* IntlSegmenterConstructor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IntlSegmenterConstructor.cpp; sourceTree = "<group>"; };
E30D903728B77F27008B2CDC /* ProxyObjectAccessCase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProxyObjectAccessCase.cpp; sourceTree = "<group>"; };
E30D903828B77F28008B2CDC /* ProxyObjectAccessCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProxyObjectAccessCase.h; sourceTree = "<group>"; };
E30E8A4C26DE2E4700DA4915 /* TemporalTimeZonePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalTimeZonePrototype.cpp; sourceTree = "<group>"; };
E30E8A4D26DE2E4700DA4915 /* TemporalTimeZone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalTimeZone.cpp; sourceTree = "<group>"; };
E30E8A4E26DE2E4700DA4915 /* TemporalTimeZonePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemporalTimeZonePrototype.h; sourceTree = "<group>"; };
@@ -5423,6 +5426,7 @@
E3400EC022A1CC78009DED54 /* FunctionExecutableInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FunctionExecutableInlines.h; sourceTree = "<group>"; };
E349A77F2491F159001BA336 /* DFGCodeOriginPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCodeOriginPool.cpp; path = dfg/DFGCodeOriginPool.cpp; sourceTree = "<group>"; };
E349A7802491F15A001BA336 /* DFGCodeOriginPool.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DFGCodeOriginPool.h; path = dfg/DFGCodeOriginPool.h; sourceTree = "<group>"; };
E34AE50028B75C07006088FA /* ProxyHelpers.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ProxyHelpers.js; sourceTree = "<group>"; };
E34E657320668E8D00FB81AC /* ParseHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseHash.h; sourceTree = "<group>"; };
E34E657420668E8E00FB81AC /* ParseHash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHash.cpp; sourceTree = "<group>"; };
E34EDBF61DB5FFC100DC87A5 /* FrameTracers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameTracers.h; sourceTree = "<group>"; };
@@ -9083,6 +9087,8 @@
14AD910A1DCA92940014F9FE /* ProgramCodeBlock.h */,
0FD3E4071B618B6600C80E1E /* PropertyCondition.cpp */,
0FD3E4081B618B6600C80E1E /* PropertyCondition.h */,
E30D903728B77F27008B2CDC /* ProxyObjectAccessCase.cpp */,
E30D903828B77F28008B2CDC /* ProxyObjectAccessCase.h */,
0F15CD201BA5F9860031FFD3 /* PutByIdFlags.cpp */,
0F15CD211BA5F9860031FFD3 /* PutByIdFlags.h */,
0F93329914CA7DC10085F3C6 /* PutByStatus.cpp */,
@@ -9383,6 +9389,7 @@
7CF9BC5E1B65D9B1009DB1EF /* PromiseConstructor.js */,
7CF9BC5D1B65D9B1009DB1EF /* PromiseOperations.js */,
7CFBAC1C18B535E500D00750 /* PromisePrototype.js */,
E34AE50028B75C07006088FA /* ProxyHelpers.js */,
7CF9BC5F1B65D9B1009DB1EF /* ReflectObject.js */,
654788421C937D2C000781A0 /* RegExpPrototype.js */,
84925A9C22B30CC800D1DFFF /* RegExpStringIteratorPrototype.js */,
@@ -10998,6 +11005,7 @@
534E03561E53BEDE00213F64 /* ProxyableAccessCase.h in Headers */,
79B00CBD1C6AB07E0088C65D /* ProxyConstructor.h in Headers */,
79B00CBF1C6AB07E0088C65D /* ProxyObject.h in Headers */,
E30D903A28B77F28008B2CDC /* ProxyObjectAccessCase.h in Headers */,
79160DBE1C8E3EC8008C085A /* ProxyRevoke.h in Headers */,
0F5780A218FE1E98001E72D9 /* PureNaN.h in Headers */,
0F15CD231BA5F9860031FFD3 /* PutByIdFlags.h in Headers */,
@@ -271,6 +271,7 @@ bytecode/PreciseJumpTargets.cpp
bytecode/ProgramCodeBlock.cpp
bytecode/PropertyCondition.cpp
bytecode/ProxyableAccessCase.cpp
bytecode/ProxyObjectAccessCase.cpp
bytecode/PutByIdFlags.cpp
bytecode/PutByStatus.cpp
bytecode/PutByVariant.cpp
@@ -180,6 +180,7 @@ namespace JSC {
macro(stringSubstringInternal) \
macro(makeBoundFunction) \
macro(hasOwnLengthProperty) \
macro(handleProxyGetTrapResult) \
macro(importModule) \
macro(copyDataProperties) \
macro(meta) \
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

@linkTimeConstant
function performProxyObjectGet(receiver, handler, propertyName)
{
"use strict";

if (handler === null)
@throwTypeError("Proxy has already been revoked. No more operations are allowed to be performed on it");

var trap = handler.get;
if (!@isCallable(trap))
return @getByValWithThis(this, receiver, propertyName);

var trapResult = trap.@call(handler, this, propertyName, receiver);

// FIXME: Add op_get_own_property bytecode and IC, which returns two values, value and attributes.
// Then we can implement it fully in JS.
@handleProxyGetTrapResult(trapResult, this, propertyName);

return trapResult;
}

0 comments on commit a328f5a

Please sign in to comment.