Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (194174 => 194175)
--- trunk/Source/_javascript_Core/ChangeLog 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-12-16 22:39:13 UTC (rev 194175)
@@ -1,5 +1,64 @@
2015-12-16 Filip Pizlo <[email protected]>
+ Improve JSObject::put performance
+ https://bugs.webkit.org/show_bug.cgi?id=152347
+
+ Reviewed by Geoffrey Garen.
+
+ This adds a new benchmark called dynbench, which just uses the C++ API to create, modify, and
+ query objects. This also adds some optimizations to make the JSObject::put code faster by making
+ it inlinable in places that really need the performance, like JITOperations and LLIntSlowPaths.
+ Inlining it is optional because the put() method is large. If you want it inlined, call
+ putInline(). There's a putInline() variant of both JSObject::put() and JSValue::put().
+
+ This is up to a 20% improvement for JSObject::put calls that get inlined all the way (like from
+ JITOperations and the new benchmark) and it's also a speed-up, albeit a smaller one, for
+ JSObject::put calls that don't get inlined (i.e. those from the DOM and the JSC C++ library code).
+ Specific speed-ups are as follows. Note that "dynamic context" means that we told PutPropertySlot
+ that we're not a static put_by_id, which turns off some type inference.
+
+ Get By Id: 2% faster
+ Put By Id Replace: 23% faster
+ Put By Id Transition + object allocation: 11% faster
+ Get By Id w/ dynamic context: 5% faster
+ Put By Id Replace w/ dynamic context: 25% faster
+ Put By Id Transition + object allocation w/ dynamic context: 10% faster
+
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * dynbench.cpp: Added.
+ (JSC::benchmarkImpl):
+ (main):
+ * jit/CallFrameShuffler32_64.cpp:
+ * jit/CallFrameShuffler64.cpp:
+ * jit/JITOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * runtime/ClassInfo.h:
+ (JSC::ClassInfo::hasStaticProperties):
+ * runtime/ConsoleClient.cpp:
+ * runtime/CustomGetterSetter.h:
+ * runtime/ErrorInstance.cpp:
+ (JSC::ErrorInstance::finishCreation):
+ (JSC::addErrorInfoAndGetBytecodeOffset): Deleted.
+ * runtime/GetterSetter.h:
+ (JSC::asGetterSetter):
+ * runtime/JSCInlines.h:
+ * runtime/JSCJSValue.h:
+ * runtime/JSCJSValueInlines.h:
+ (JSC::JSValue::put):
+ (JSC::JSValue::putInternal):
+ (JSC::JSValue::putByIndex):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::put):
+ (JSC::JSObject::putByIndex):
+ * runtime/JSObject.h:
+ (JSC::JSObject::getVectorLength):
+ (JSC::JSObject::inlineGetOwnPropertySlot):
+ (JSC::JSObject::get):
+ (JSC::JSObject::putDirectInternal):
+
+2015-12-16 Filip Pizlo <[email protected]>
+
Work around a bug in LLVM by flipping the unification order
https://bugs.webkit.org/show_bug.cgi?id=152341
rdar://problem/23920749
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (194174 => 194175)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2015-12-16 22:39:13 UTC (rev 194175)
@@ -25,6 +25,7 @@
buildPhases = (
);
dependencies = (
+ 0F93275D1C20BF3A00CF6564 /* PBXTargetDependency */,
0FEC85B11BDB5D8F0080FF74 /* PBXTargetDependency */,
5D6B2A4F152B9E23005231DE /* PBXTargetDependency */,
5D6B2A51152B9E23005231DE /* PBXTargetDependency */,
@@ -482,6 +483,10 @@
0F919D2615853CE3004A4E7D /* Watchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D2315853CDE004A4E7D /* Watchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D2715856770004A4E7D /* SymbolTable.cpp */; };
0F93274D1C1F66AA00CF6564 /* GPRInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93274C1C1F66AA00CF6564 /* GPRInfo.cpp */; };
+ 0F9327521C20BCBA00CF6564 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51F0EB6105C86C6B00E6DF1B /* Foundation.framework */; };
+ 0F9327531C20BCBA00CF6564 /* _javascript_Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* _javascript_Core.framework */; };
+ 0F93275B1C20BCDF00CF6564 /* dynbench.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93275A1C20BCDF00CF6564 /* dynbench.cpp */; };
+ 0F93275F1C21EF7F00CF6564 /* JSObjectInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93275E1C21EF7F00CF6564 /* JSObjectInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */; };
0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */; };
@@ -2057,6 +2062,13 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ 0F93275C1C20BF3A00CF6564 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0F93274E1C20BCBA00CF6564;
+ remoteInfo = dynbench;
+ };
0FCEFABC1805D66300472CE4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
@@ -2594,6 +2606,9 @@
0F919D2315853CDE004A4E7D /* Watchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchpoint.h; sourceTree = "<group>"; };
0F919D2715856770004A4E7D /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; };
0F93274C1C1F66AA00CF6564 /* GPRInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GPRInfo.cpp; sourceTree = "<group>"; };
+ 0F9327591C20BCBA00CF6564 /* dynbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dynbench; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0F93275A1C20BCDF00CF6564 /* dynbench.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dynbench.cpp; sourceTree = "<group>"; };
+ 0F93275E1C21EF7F00CF6564 /* JSObjectInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObjectInlines.h; sourceTree = "<group>"; };
0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallLinkStatus.cpp; sourceTree = "<group>"; };
0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallLinkStatus.h; sourceTree = "<group>"; };
0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetByIdStatus.cpp; sourceTree = "<group>"; };
@@ -4252,6 +4267,15 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 0F9327511C20BCBA00CF6564 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0F9327521C20BCBA00CF6564 /* Foundation.framework in Frameworks */,
+ 0F9327531C20BCBA00CF6564 /* _javascript_Core.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
0FCEFAB31805D61600472CE4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -4339,6 +4363,7 @@
14BD59BF0A3E8F9000BAF59C /* testapi */,
0FEC85AD1BDB5CF10080FF74 /* testb3 */,
6511230514046A4C002B101D /* testRegExp */,
+ 0F9327591C20BCBA00CF6564 /* dynbench */,
);
name = Products;
sourceTree = "<group>";
@@ -4348,14 +4373,15 @@
0867D691FE84028FC02AAC07 /* _javascript_Core */ = {
isa = PBXGroup;
children = (
- 6529FB3018B2D63900C61102 /* generate-bytecode-files */,
8604F4F2143A6C4400B295F5 /* ChangeLog */,
+ F68EBB8C0255D4C601FF60F7 /* config.h */,
F692A8540255597D01FF60F7 /* create_hash_table */,
A718F8211178EB4B002465A7 /* create_regex_tables */,
+ 937B63CC09E766D200A671DD /* DerivedSources.make */,
+ 0F93275A1C20BCDF00CF6564 /* dynbench.cpp */,
+ 6529FB3018B2D63900C61102 /* generate-bytecode-files */,
+ F5C290E60284F98E018635CA /* _javascript_CorePrefix.h */,
45E12D8806A49B0F00E9DF84 /* jsc.cpp */,
- F68EBB8C0255D4C601FF60F7 /* config.h */,
- F5C290E60284F98E018635CA /* _javascript_CorePrefix.h */,
- 937B63CC09E766D200A671DD /* DerivedSources.make */,
A7C225CC139981F100FF1662 /* KeywordLookupGenerator.py */,
1432EBD70A34CAD400717B9F /* API */,
9688CB120ED12B4E001D649F /* assembler */,
@@ -4364,9 +4390,12 @@
A7D8019F1880D66E0026C39B /* builtins */,
969A078F0ED1D3AE00F1F681 /* bytecode */,
7E39D81D0EC38EFA003AF11A /* bytecompiler */,
+ 1C90513E0BA9E8830081E9D0 /* Configurations */,
1480DB9A0DDC2231003CFDF2 /* debugger */,
+ 650FDF8D09D0FCA700769E54 /* Derived Sources */,
86EC9DB31328DF44002B2AD7 /* dfg */,
0FF4272E158EBCCE004CB9FF /* disassembler */,
+ 0867D69AFE84028FC02AAC07 /* Frameworks */,
0FEA09FC1705137F00BB722C /* ftl */,
142E312A134FF0A600AFADB5 /* heap */,
A5BA15DF1823409200A82E69 /* inspector */,
@@ -4375,19 +4404,16 @@
0F46809C14BA7F4D00BFE272 /* llint */,
0FCEFAAD1805CA4400472CE4 /* llvm */,
7E39D8370EC3A388003AF11A /* parser */,
+ 034768DFFF38A50411DB9C8B /* Products */,
95AB831A0DA42C6900BC83F3 /* profiler */,
99E45A0C18A01E930026D88F /* replay */,
+ 932FC3C20824BB70005B3C75 /* Resources */,
7EF6E0BB0EB7A1EC0079AFAF /* runtime */,
+ 9959E9251BD17F1E001AA413 /* Scripts */,
141211000A48772600480255 /* tests */,
8603CEF014C753EF00AE59E3 /* tools */,
7B98D1331B60CD1E0023B1A4 /* wasm */,
86EAC48C0F93E8B9008EC948 /* yarr */,
- 650FDF8D09D0FCA700769E54 /* Derived Sources */,
- 932FC3C20824BB70005B3C75 /* Resources */,
- 9959E9251BD17F1E001AA413 /* Scripts */,
- 0867D69AFE84028FC02AAC07 /* Frameworks */,
- 034768DFFF38A50411DB9C8B /* Products */,
- 1C90513E0BA9E8830081E9D0 /* Configurations */,
);
name = _javascript_Core;
sourceTree = "<group>";
@@ -5523,9 +5549,9 @@
E178633F0D9BEC0000D74E75 /* InitializeThreading.h */,
E35E035D1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp */,
E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */,
+ A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */,
A7A8AF2C17ADB5F3005AB174 /* Int16Array.h */,
A7A8AF2D17ADB5F3005AB174 /* Int32Array.h */,
- A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */,
BC9BB95B0E19680600DF8855 /* InternalFunction.cpp */,
BC11667A0E199C05008066DD /* InternalFunction.h */,
A1B9E2331B4E0D6700BC7FED /* IntlCollator.cpp */,
@@ -5614,9 +5640,9 @@
A59455911824744700CC3843 /* JSGlobalObjectDebuggable.h */,
BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */,
BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */,
+ 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */,
0F2B66CA17B6B5AB00A7AE3F /* JSInt16Array.h */,
0F2B66CB17B6B5AB00A7AE3F /* JSInt32Array.h */,
- 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */,
E33F507E1B8429A400413856 /* JSInternalPromise.cpp */,
E33F507F1B8429A400413856 /* JSInternalPromise.h */,
E33F50761B84225700413856 /* JSInternalPromiseConstructor.cpp */,
@@ -5647,6 +5673,7 @@
A72700770DAC605600E548D7 /* JSNotAnObject.h */,
BC22A3980E16E14800AF21C8 /* JSObject.cpp */,
BC22A3990E16E14800AF21C8 /* JSObject.h */,
+ 0F93275E1C21EF7F00CF6564 /* JSObjectInlines.h */,
A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */,
A7F9935D0FD7325100A0B2D0 /* JSONObject.h */,
7C184E1817BEDBD3007CB63A /* JSPromise.cpp */,
@@ -5694,10 +5721,10 @@
53F256E11B87E28000B4B768 /* JSTypedArrayViewPrototype.cpp */,
53917E7C1B791106000EBD33 /* JSTypedArrayViewPrototype.h */,
6507D2970E871E4A00D7D896 /* JSTypeInfo.h */,
+ 0F2B66D217B6B5AB00A7AE3F /* JSUint8Array.h */,
+ 0F2B66D317B6B5AB00A7AE3F /* JSUint8ClampedArray.h */,
0F2B66D417B6B5AB00A7AE3F /* JSUint16Array.h */,
0F2B66D517B6B5AB00A7AE3F /* JSUint32Array.h */,
- 0F2B66D217B6B5AB00A7AE3F /* JSUint8Array.h */,
- 0F2B66D317B6B5AB00A7AE3F /* JSUint8ClampedArray.h */,
A7CA3AE117DA41AE006538AF /* JSWeakMap.cpp */,
A7CA3AE217DA41AE006538AF /* JSWeakMap.h */,
709FB8611AE335C60039D069 /* JSWeakSet.cpp */,
@@ -5871,11 +5898,11 @@
0F2D4DE019832D91007D4B19 /* TypeProfilerLog.h */,
0F2D4DE319832D91007D4B19 /* TypeSet.cpp */,
0F2D4DE419832D91007D4B19 /* TypeSet.h */,
+ A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */,
+ A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */,
A7A8AF3217ADB5F3005AB174 /* Uint16Array.h */,
866739D113BFDE710023D87C /* Uint16WithFraction.h */,
A7A8AF3317ADB5F3005AB174 /* Uint32Array.h */,
- A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */,
- A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */,
0FE050231AA9095600D33B33 /* VarOffset.cpp */,
0FE050241AA9095600D33B33 /* VarOffset.h */,
E18E3A570DF9278C00D90B34 /* VM.cpp */,
@@ -7752,6 +7779,7 @@
0F5780A218FE1E98001E72D9 /* PureNaN.h in Headers */,
0F15CD231BA5F9860031FFD3 /* PutByIdFlags.h in Headers */,
0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */,
+ 0F93275F1C21EF7F00CF6564 /* JSObjectInlines.h in Headers */,
0F93B4AA18B92C4D00178A3F /* PutByIdVariant.h in Headers */,
0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */,
0F9FC8C514E1B60400D52AE0 /* PutKind.h in Headers */,
@@ -7950,6 +7978,22 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ 0F93274E1C20BCBA00CF6564 /* dynbench */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 0F9327541C20BCBA00CF6564 /* Build configuration list for PBXNativeTarget "dynbench" */;
+ buildPhases = (
+ 0F93274F1C20BCBA00CF6564 /* Sources */,
+ 0F9327511C20BCBA00CF6564 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dynbench;
+ productName = testapi;
+ productReference = 0F9327591C20BCBA00CF6564 /* dynbench */;
+ productType = "com.apple.product-type.tool";
+ };
0FCEFAB51805D61600472CE4 /* llvmForJSC */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0FCEFAB71805D61600472CE4 /* Build configuration list for PBXNativeTarget "llvmForJSC" */;
@@ -8140,6 +8184,7 @@
651122F714046A4C002B101D /* testRegExp */,
0FEC85941BDB5CF10080FF74 /* testb3 */,
5D6B2A47152B9E17005231DE /* Test Tools */,
+ 0F93274E1C20BCBA00CF6564 /* dynbench */,
);
};
/* End PBXProject section */
@@ -8376,6 +8421,14 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 0F93274F1C20BCBA00CF6564 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0F93275B1C20BCDF00CF6564 /* dynbench.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
0FCEFAB21805D61600472CE4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -9235,6 +9288,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ 0F93275D1C20BF3A00CF6564 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0F93274E1C20BCBA00CF6564 /* dynbench */;
+ targetProxy = 0F93275C1C20BF3A00CF6564 /* PBXContainerItemProxy */;
+ };
0FCEFABD1805D66300472CE4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0FCEFAB51805D61600472CE4 /* llvmForJSC */;
@@ -9341,6 +9399,34 @@
};
name = Production;
};
+ 0F9327551C20BCBA00CF6564 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 0F9327561C20BCBA00CF6564 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 0F9327571C20BCBA00CF6564 /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
+ buildSettings = {
+ };
+ name = Profiling;
+ };
+ 0F9327581C20BCBA00CF6564 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
+ buildSettings = {
+ };
+ name = Production;
+ };
0FCEFAB81805D61600472CE4 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0FCEFABE1805D86900472CE4 /* LLVMForJSC.xcconfig */;
@@ -9742,6 +9828,17 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Production;
};
+ 0F9327541C20BCBA00CF6564 /* Build configuration list for PBXNativeTarget "dynbench" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 0F9327551C20BCBA00CF6564 /* Debug */,
+ 0F9327561C20BCBA00CF6564 /* Release */,
+ 0F9327571C20BCBA00CF6564 /* Profiling */,
+ 0F9327581C20BCBA00CF6564 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
0FCEFAB71805D61600472CE4 /* Build configuration list for PBXNativeTarget "llvmForJSC" */ = {
isa = XCConfigurationList;
buildConfigurations = (
Added: trunk/Source/_javascript_Core/dynbench.cpp (0 => 194175)
--- trunk/Source/_javascript_Core/dynbench.cpp (rev 0)
+++ trunk/Source/_javascript_Core/dynbench.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "config.h"
+
+#include "Identifier.h"
+#include "InitializeThreading.h"
+#include "JSCInlines.h"
+#include "JSCJSValue.h"
+#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "JSObject.h"
+#include "VM.h"
+
+using namespace JSC;
+
+namespace {
+
+StaticLock crashLock;
+const char* nameFilter;
+unsigned requestedIterationCount;
+
+#define CHECK(x) do { \
+ if (!!(x)) \
+ break; \
+ crashLock.lock(); \
+ WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
+ CRASH(); \
+ } while (false)
+
+template<typename Callback>
+NEVER_INLINE void benchmarkImpl(const char* name, unsigned iterationCount, const Callback& callback)
+{
+ if (nameFilter && !strcasestr(name, nameFilter))
+ return;
+
+ if (requestedIterationCount)
+ iterationCount = requestedIterationCount;
+
+ double before = monotonicallyIncreasingTimeMS();
+ callback(iterationCount);
+ double after = monotonicallyIncreasingTimeMS();
+ dataLog(name, ": ", after - before, " ms.\n");
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv)
+{
+ if (argc >= 2) {
+ if (argv[1][0] == '-') {
+ dataLog("Usage: dynbench [<filter> [<iteration count>]]\n");
+ return 1;
+ }
+
+ nameFilter = argv[1];
+
+ if (argc >= 3) {
+ if (sscanf(argv[2], "%u", &requestedIterationCount) != 1) {
+ dataLog("Could not parse iteration count ", argv[2], "\n");
+ return 1;
+ }
+ }
+ }
+
+ WTF::initializeMainThread();
+ JSC::initializeThreading();
+
+ VM* vm = &VM::create(LargeHeap).leakRef();
+ {
+ JSLockHolder locker(vm);
+
+ JSGlobalObject* globalObject =
+ JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
+ ExecState* exec = globalObject->globalExec();
+
+ Identifier identF = Identifier::fromString(exec, "f");
+ Identifier identG = Identifier::fromString(exec, "g");
+
+ Structure* objectStructure =
+ JSFinalObject::createStructure(*vm, globalObject, globalObject->objectPrototype(), 2);
+
+ // Non-strict dynamic get by id:
+ JSValue object = JSFinalObject::create(*vm, objectStructure);
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identF, jsNumber(42), slot);
+ }
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identG, jsNumber(43), slot);
+ }
+ benchmarkImpl(
+ "Non Strict Dynamic Get By Id",
+ 1000000,
+ [&] (unsigned iterationCount) {
+ for (unsigned i = iterationCount; i--;) {
+ JSValue result = object.get(exec, identF);
+ CHECK(result == jsNumber(42));
+ result = object.get(exec, identG);
+ CHECK(result == jsNumber(43));
+ }
+ });
+
+ // Non-strict dynamic put by id replace:
+ object = JSFinalObject::create(*vm, objectStructure);
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identF, jsNumber(42), slot);
+ }
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identG, jsNumber(43), slot);
+ }
+ benchmarkImpl(
+ "Non Strict Dynamic Put By Id Replace",
+ 1000000,
+ [&] (unsigned iterationCount) {
+ for (unsigned i = iterationCount; i--;) {
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identF, jsNumber(i), slot);
+ }
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identG, jsNumber(i), slot);
+ }
+ }
+ });
+
+ // Non-strict dynamic put by id transition with object allocation:
+ benchmarkImpl(
+ "Non Strict Dynamic Allocation and Put By Id Transition",
+ 1000000,
+ [&] (unsigned iterationCount) {
+ for (unsigned i = iterationCount; i--;) {
+ JSValue object = JSFinalObject::create(*vm, objectStructure);
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identF, jsNumber(i), slot);
+ }
+ {
+ PutPropertySlot slot(object, false, PutPropertySlot::PutById);
+ object.putInline(exec, identG, jsNumber(i), slot);
+ }
+ }
+ });
+
+ // Non-strict dynamic get by id with dynamic store context:
+ object = JSFinalObject::create(*vm, objectStructure);
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identF, jsNumber(42), slot);
+ }
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identG, jsNumber(43), slot);
+ }
+ benchmarkImpl(
+ "Non Strict Dynamic Get By Id With Dynamic Store Context",
+ 1000000,
+ [&] (unsigned iterationCount) {
+ for (unsigned i = iterationCount; i--;) {
+ JSValue result = object.get(exec, identF);
+ CHECK(result == jsNumber(42));
+ result = object.get(exec, identG);
+ CHECK(result == jsNumber(43));
+ }
+ });
+
+ // Non-strict dynamic put by id replace with dynamic store context:
+ object = JSFinalObject::create(*vm, objectStructure);
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identF, jsNumber(42), slot);
+ }
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identG, jsNumber(43), slot);
+ }
+ benchmarkImpl(
+ "Non Strict Dynamic Put By Id Replace With Dynamic Store Context",
+ 1000000,
+ [&] (unsigned iterationCount) {
+ for (unsigned i = iterationCount; i--;) {
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identF, jsNumber(i), slot);
+ }
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identG, jsNumber(i), slot);
+ }
+ }
+ });
+
+ // Non-strict dynamic put by id transition with object allocation with dynamic store context:
+ benchmarkImpl(
+ "Non Strict Dynamic Allocation and Put By Id Transition With Dynamic Store Context",
+ 1000000,
+ [&] (unsigned iterationCount) {
+ for (unsigned i = iterationCount; i--;) {
+ JSValue object = JSFinalObject::create(*vm, objectStructure);
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identF, jsNumber(i), slot);
+ }
+ {
+ PutPropertySlot slot(object, false);
+ object.putInline(exec, identG, jsNumber(i), slot);
+ }
+ }
+ });
+ }
+
+ crashLock.lock();
+ return 0;
+}
+
Modified: trunk/Source/_javascript_Core/jit/CallFrameShuffler32_64.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/jit/CallFrameShuffler32_64.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/jit/CallFrameShuffler32_64.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -30,7 +30,7 @@
#include "CCallHelpers.h"
#include "DataFormat.h"
-#include "JSCJSValueInlines.h"
+#include "JSCInlines.h"
namespace JSC {
Modified: trunk/Source/_javascript_Core/jit/CallFrameShuffler64.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/jit/CallFrameShuffler64.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/jit/CallFrameShuffler64.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -30,7 +30,7 @@
#include "CCallHelpers.h"
#include "DataFormat.h"
-#include "JSCJSValueInlines.h"
+#include "JSCInlines.h"
namespace JSC {
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -248,7 +248,7 @@
Identifier ident = Identifier::fromUid(vm, uid);
PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext());
- JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot);
+ JSValue::decode(encodedBase).putInline(exec, ident, JSValue::decode(encodedValue), slot);
}
void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
@@ -260,7 +260,7 @@
Identifier ident = Identifier::fromUid(vm, uid);
PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext());
- JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot);
+ JSValue::decode(encodedBase).putInline(exec, ident, JSValue::decode(encodedValue), slot);
}
void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
@@ -300,7 +300,7 @@
PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
- baseValue.put(exec, ident, value, slot);
+ baseValue.putInline(exec, ident, value, slot);
if (accessType != static_cast<AccessType>(stubInfo->accessType))
return;
@@ -322,7 +322,7 @@
PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
- baseValue.put(exec, ident, value, slot);
+ baseValue.putInline(exec, ident, value, slot);
if (accessType != static_cast<AccessType>(stubInfo->accessType))
return;
@@ -422,7 +422,7 @@
byValInfo->tookSlowPath = true;
PutPropertySlot slot(baseValue, callFrame->codeBlock()->isStrictMode());
- baseValue.put(callFrame, property, value, slot);
+ baseValue.putInline(callFrame, property, value, slot);
}
static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ByValInfo* byValInfo)
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -620,7 +620,7 @@
if (pc[8].u.putByIdFlags & PutByIdIsDirect)
asObject(baseValue)->putDirect(vm, ident, LLINT_OP_C(3).jsValue(), slot);
else
- baseValue.put(exec, ident, LLINT_OP_C(3).jsValue(), slot);
+ baseValue.putInline(exec, ident, LLINT_OP_C(3).jsValue(), slot);
LLINT_CHECK_EXCEPTION();
if (!LLINT_ALWAYS_ACCESS_SLOW
Modified: trunk/Source/_javascript_Core/runtime/ClassInfo.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/ClassInfo.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/ClassInfo.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -181,7 +181,7 @@
return false;
}
- bool hasStaticSetterOrReadonlyProperties() const;
+ JS_EXPORT_PRIVATE bool hasStaticSetterOrReadonlyProperties() const;
const HashTable* staticPropHashTable;
Modified: trunk/Source/_javascript_Core/runtime/ConsoleClient.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/ConsoleClient.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/ConsoleClient.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -26,6 +26,7 @@
#include "config.h"
#include "ConsoleClient.h"
+#include "JSCInlines.h"
#include "ScriptArguments.h"
#include "ScriptCallStack.h"
#include "ScriptCallStackFactory.h"
Modified: trunk/Source/_javascript_Core/runtime/CustomGetterSetter.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/CustomGetterSetter.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/CustomGetterSetter.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -70,7 +70,7 @@
CustomSetter m_setter;
};
-void callCustomSetter(ExecState*, JSValue customGetterSetter, JSObject* base, JSValue thisValue, JSValue value);
+JS_EXPORT_PRIVATE void callCustomSetter(ExecState*, JSValue customGetterSetter, JSObject* base, JSValue thisValue, JSValue value);
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -128,50 +128,6 @@
unsigned m_index;
};
-static bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset)
-{
- Vector<StackFrame> stackTrace = Vector<StackFrame>();
-
- if (exec && stackTrace.isEmpty())
- vm.interpreter->getStackTrace(stackTrace);
-
- if (!stackTrace.isEmpty()) {
-
- ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
-
- StackFrame* stackFrame;
- for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
- stackFrame = &stackTrace.at(i);
- if (stackFrame->bytecodeOffset)
- break;
- }
-
- if (bytecodeOffset) {
- FindFirstCallerFrameWithCodeblockFunctor functor(exec);
- vm.topCallFrame->iterate(functor);
- callFrame = functor.foundCallFrame();
- unsigned stackIndex = functor.index();
- bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset;
- }
-
- unsigned line;
- unsigned column;
- stackFrame->computeLineAndColumn(line, column);
- obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete);
- obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete);
-
- if (!stackFrame->sourceURL.isEmpty())
- obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete);
-
- if (!useCurrentFrame)
- stackTrace.remove(0);
- obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
-
- return true;
- }
- return false;
-}
-
void ErrorInstance::finishCreation(ExecState* exec, VM& vm, const String& message, bool useCurrentFrame)
{
Base::finishCreation(vm);
Modified: trunk/Source/_javascript_Core/runtime/GetterSetter.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/GetterSetter.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/GetterSetter.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -144,7 +144,7 @@
}
JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter);
-void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue, ECMAMode);
+JS_EXPORT_PRIVATE void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue, ECMAMode);
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSCInlines.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/JSCInlines.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/JSCInlines.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -45,6 +45,7 @@
#include "JSArrayBufferViewInlines.h"
#include "JSCJSValueInlines.h"
#include "JSFunctionInlines.h"
+#include "JSObjectInlines.h"
#include "JSProxy.h"
#include "JSString.h"
#include "Operations.h"
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValue.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/JSCJSValue.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValue.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -277,6 +277,7 @@
bool getPropertySlot(ExecState*, PropertyName, PropertySlot&) const;
void put(ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ void putInline(ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -31,6 +31,7 @@
#include "InternalFunction.h"
#include "JSCJSValue.h"
#include "JSCellInlines.h"
+#include "JSObject.h"
#include "JSFunction.h"
#include <wtf/text/StringImpl.h>
@@ -751,6 +752,24 @@
asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot);
}
+ALWAYS_INLINE void JSValue::putInline(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ if (UNLIKELY(!isCell())) {
+ putToPrimitive(exec, propertyName, value, slot);
+ return;
+ }
+ JSCell* cell = asCell();
+ auto putMethod = cell->methodTable(exec->vm())->put;
+ if (LIKELY(putMethod == JSObject::put)) {
+ JSObject::putInline(cell, exec, propertyName, value, slot);
+ return;
+ }
+
+ PutPropertySlot otherSlot = slot;
+ putMethod(cell, exec, propertyName, value, otherSlot);
+ slot = otherSlot;
+}
+
inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
{
if (UNLIKELY(!isCell())) {
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2015-12-16 22:39:13 UTC (rev 194175)
@@ -372,40 +372,20 @@
// ECMA 8.6.2.2
void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
- JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT(value);
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+ putInline(cell, exec, propertyName, value, slot);
+}
+
+void JSObject::putInlineSlow(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
VM& vm = exec->vm();
-
- // Try indexed put first. This is required for correctness, since loads on property names that appear like
- // valid indices will never look in the named property storage.
- if (Optional<uint32_t> index = parseIndex(propertyName)) {
- putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
- return;
- }
-
- // Check if there are any setters or getters in the prototype chain
- JSValue prototype;
- if (propertyName != exec->propertyNames().underscoreProto) {
- for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
- prototype = obj->prototype();
- if (prototype.isNull()) {
- ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot)
- && slot.isStrictMode())
- throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
- }
- }
- }
- JSObject* obj;
- for (obj = thisObject; ; obj = asObject(prototype)) {
+ JSObject* obj = this;
+ for (;;) {
unsigned attributes;
PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes);
if (isValidOffset(offset)) {
if (attributes & ReadOnly) {
- ASSERT(thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
+ ASSERT(structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == this);
if (slot.isStrictMode())
exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
return;
@@ -413,8 +393,8 @@
JSValue gs = obj->getDirect(offset);
if (gs.isGetterSetter()) {
- callSetter(exec, cell, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
- if (!thisObject->structure()->isDictionary())
+ callSetter(exec, this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
+ if (!structure()->isDictionary())
slot.setCacheableSetter(obj, offset);
return;
}
@@ -438,15 +418,15 @@
}
}
}
- prototype = obj->prototype();
+ JSValue prototype = obj->prototype();
if (prototype.isNull())
break;
+ obj = asObject(prototype);
}
- ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) && slot.isStrictMode())
+ ASSERT(!structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == this);
+ if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
}
void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -140,7 +140,9 @@
return 0;
return m_butterfly.get(this)->vectorLength();
}
-
+
+ static void putInline(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
@@ -852,11 +854,13 @@
template<PutMode>
bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
+ JS_EXPORT_PRIVATE NEVER_INLINE void putInlineSlow(ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
bool inlineGetOwnPropertySlot(VM&, Structure&, PropertyName, PropertySlot&);
JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned, Structure&);
- const HashTableValue* findPropertyHashEntry(PropertyName) const;
+ JS_EXPORT_PRIVATE const HashTableValue* findPropertyHashEntry(PropertyName) const;
void putIndexedDescriptor(ExecState*, SparseArrayEntry*, const PropertyDescriptor&, PropertyDescriptor& old);
@@ -1090,13 +1094,23 @@
return false;
JSValue value = getDirect(offset);
- if (structure.hasGetterSetterProperties() && value.isGetterSetter())
- fillGetterPropertySlot(slot, value, attributes, offset);
- else if (structure.hasCustomGetterSetterProperties() && value.isCustomGetterSetter())
- fillCustomGetterPropertySlot(slot, value, attributes, structure);
- else
- slot.setValue(this, attributes, value, offset);
-
+ if (value.isCell()) {
+ ASSERT(value);
+ JSCell* cell = value.asCell();
+ JSType type = cell->type();
+ switch (type) {
+ case GetterSetterType:
+ fillGetterPropertySlot(slot, value, attributes, offset);
+ return true;
+ case CustomGetterSetterType:
+ fillCustomGetterPropertySlot(slot, value, attributes, structure);
+ return true;
+ default:
+ break;
+ }
+ }
+
+ slot.setValue(this, attributes, value, offset);
return true;
}
@@ -1187,7 +1201,7 @@
}
template<JSObject::PutMode mode>
-inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
+ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
{
ASSERT(value);
ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
Added: trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (0 => 194175)
--- trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/JSObjectInlines.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten ([email protected])
+ * Copyright (C) 2001 Peter Kelly ([email protected])
+ * Copyright (C) 2003-2006, 2008, 2009, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel ([email protected])
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSObjectInlines_h
+#define JSObjectInlines_h
+
+#include "Error.h"
+#include "JSObject.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+// ECMA 8.6.2.2
+ALWAYS_INLINE void JSObject::putInline(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ ASSERT(value);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+ VM& vm = exec->vm();
+
+ // Try indexed put first. This is required for correctness, since loads on property names that appear like
+ // valid indices will never look in the named property storage.
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
+ return;
+ }
+
+ // Check if there are any setters or getters in the prototype chain
+ JSValue prototype;
+ if (propertyName != exec->propertyNames().underscoreProto) {
+ for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
+ prototype = obj->prototype();
+ if (prototype.isNull()) {
+ ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
+ if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot)
+ && slot.isStrictMode())
+ throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+ }
+ }
+
+ thisObject->putInlineSlow(exec, propertyName, value, slot);
+}
+
+} // namespace JSC
+
+#endif // JSObjectInlines_h
+
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (194174 => 194175)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2015-12-16 22:08:06 UTC (rev 194174)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2015-12-16 22:39:13 UTC (rev 194175)
@@ -258,7 +258,7 @@
static void visitChildren(JSCell*, SlotVisitor&);
// Will just the prototype chain intercept this property access?
- bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
+ JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
Structure* previousID() const
{