Title: [199240] trunk
Revision
199240
Author
[email protected]
Date
2016-04-08 12:37:04 -0700 (Fri, 08 Apr 2016)

Log Message

Add IC support for arguments.length
https://bugs.webkit.org/show_bug.cgi?id=156389

Reviewed by Geoffrey Garen.
Source/_javascript_Core:

        
This adds support for caching accesses to arguments.length for both DirectArguments and
ScopedArguments. In strict mode, we already cached these accesses since they were just
normal properties.

Amazingly, we also already supported caching of overridden arguments.length in both
DirectArguments and ScopedArguments. This is because when you override, the property gets
materialized as a normal JS property and the structure is changed.
        
This patch painstakingly preserves our previous caching of overridden length while
introducing caching of non-overridden length (i.e. the common case). In fact, we even cache
the case where it could either be overridden or not, since we just end up with an AccessCase
for each and they cascade to each other.

This is a >3x speed-up on microbenchmarks that do arguments.length in a polymorphic context.
Entirely monomorphic accesses were already handled by the DFG.

* bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
(JSC::AccessCase::guardedByStructureCheck):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generate):
(WTF::printInternal):
* bytecode/PolymorphicAccess.h:
* jit/ICStats.h:
* jit/JITOperations.cpp:
* jit/Repatch.cpp:
(JSC::tryCacheGetByID):
(JSC::tryCachePutByID):
(JSC::tryRepatchIn):
* tests/stress/direct-arguments-override-length-then-access-normal-length.js: Added.
(args):
(foo):
(result.foo):

LayoutTests:


* js/regress/direct-arguments-length-expected.txt: Added.
* js/regress/direct-arguments-length.html: Added.
* js/regress/direct-arguments-overridden-length-expected.txt: Added.
* js/regress/direct-arguments-overridden-length.html: Added.
* js/regress/direct-arguments-possibly-overridden-length-expected.txt: Added.
* js/regress/direct-arguments-possibly-overridden-length.html: Added.
* js/regress/scoped-arguments-length-expected.txt: Added.
* js/regress/scoped-arguments-length.html: Added.
* js/regress/scoped-arguments-overridden-length-expected.txt: Added.
* js/regress/scoped-arguments-overridden-length.html: Added.
* js/regress/scoped-arguments-possibly-overridden-length-expected.txt: Added.
* js/regress/scoped-arguments-possibly-overridden-length.html: Added.
* js/regress/script-tests/direct-arguments-length.js: Added.
(args):
* js/regress/script-tests/direct-arguments-overridden-length.js: Added.
(args):
* js/regress/script-tests/direct-arguments-possibly-overridden-length.js: Added.
(args1):
(args2):
* js/regress/script-tests/scoped-arguments-length.js: Added.
(args):
* js/regress/script-tests/scoped-arguments-overridden-length.js: Added.
(args):
* js/regress/script-tests/scoped-arguments-possibly-overridden-length.js: Added.
(args1):
(args2):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (199239 => 199240)


--- trunk/LayoutTests/ChangeLog	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/LayoutTests/ChangeLog	2016-04-08 19:37:04 UTC (rev 199240)
@@ -1,3 +1,37 @@
+2016-04-08  Filip Pizlo  <[email protected]>
+
+        Add IC support for arguments.length
+        https://bugs.webkit.org/show_bug.cgi?id=156389
+
+        Reviewed by Geoffrey Garen.
+
+        * js/regress/direct-arguments-length-expected.txt: Added.
+        * js/regress/direct-arguments-length.html: Added.
+        * js/regress/direct-arguments-overridden-length-expected.txt: Added.
+        * js/regress/direct-arguments-overridden-length.html: Added.
+        * js/regress/direct-arguments-possibly-overridden-length-expected.txt: Added.
+        * js/regress/direct-arguments-possibly-overridden-length.html: Added.
+        * js/regress/scoped-arguments-length-expected.txt: Added.
+        * js/regress/scoped-arguments-length.html: Added.
+        * js/regress/scoped-arguments-overridden-length-expected.txt: Added.
+        * js/regress/scoped-arguments-overridden-length.html: Added.
+        * js/regress/scoped-arguments-possibly-overridden-length-expected.txt: Added.
+        * js/regress/scoped-arguments-possibly-overridden-length.html: Added.
+        * js/regress/script-tests/direct-arguments-length.js: Added.
+        (args):
+        * js/regress/script-tests/direct-arguments-overridden-length.js: Added.
+        (args):
+        * js/regress/script-tests/direct-arguments-possibly-overridden-length.js: Added.
+        (args1):
+        (args2):
+        * js/regress/script-tests/scoped-arguments-length.js: Added.
+        (args):
+        * js/regress/script-tests/scoped-arguments-overridden-length.js: Added.
+        (args):
+        * js/regress/script-tests/scoped-arguments-possibly-overridden-length.js: Added.
+        (args1):
+        (args2):
+
 2016-04-08  Joseph Pecoraro  <[email protected]>
 
         Redefining a method of the same name hits an assertion

Added: trunk/LayoutTests/js/regress/direct-arguments-length-expected.txt (0 => 199240)


--- trunk/LayoutTests/js/regress/direct-arguments-length-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/direct-arguments-length-expected.txt	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,10 @@
+JSRegress/direct-arguments-length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/direct-arguments-length.html (0 => 199240)


--- trunk/LayoutTests/js/regress/direct-arguments-length.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/direct-arguments-length.html	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/direct-arguments-overridden-length-expected.txt (0 => 199240)


--- trunk/LayoutTests/js/regress/direct-arguments-overridden-length-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/direct-arguments-overridden-length-expected.txt	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,10 @@
+JSRegress/direct-arguments-overridden-length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/direct-arguments-overridden-length.html (0 => 199240)


--- trunk/LayoutTests/js/regress/direct-arguments-overridden-length.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/direct-arguments-overridden-length.html	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/direct-arguments-possibly-overridden-length-expected.txt (0 => 199240)


--- trunk/LayoutTests/js/regress/direct-arguments-possibly-overridden-length-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/direct-arguments-possibly-overridden-length-expected.txt	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,10 @@
+JSRegress/direct-arguments-possibly-overridden-length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/direct-arguments-possibly-overridden-length.html (0 => 199240)


--- trunk/LayoutTests/js/regress/direct-arguments-possibly-overridden-length.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/direct-arguments-possibly-overridden-length.html	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/scoped-arguments-length-expected.txt (0 => 199240)


--- trunk/LayoutTests/js/regress/scoped-arguments-length-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/scoped-arguments-length-expected.txt	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,10 @@
+JSRegress/scoped-arguments-length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/scoped-arguments-length.html (0 => 199240)


--- trunk/LayoutTests/js/regress/scoped-arguments-length.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/scoped-arguments-length.html	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/scoped-arguments-overridden-length-expected.txt (0 => 199240)


--- trunk/LayoutTests/js/regress/scoped-arguments-overridden-length-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/scoped-arguments-overridden-length-expected.txt	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,10 @@
+JSRegress/scoped-arguments-overridden-length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/scoped-arguments-overridden-length.html (0 => 199240)


--- trunk/LayoutTests/js/regress/scoped-arguments-overridden-length.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/scoped-arguments-overridden-length.html	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/scoped-arguments-possibly-overridden-length-expected.txt (0 => 199240)


--- trunk/LayoutTests/js/regress/scoped-arguments-possibly-overridden-length-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/scoped-arguments-possibly-overridden-length-expected.txt	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,10 @@
+JSRegress/scoped-arguments-possibly-overridden-length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/scoped-arguments-possibly-overridden-length.html (0 => 199240)


--- trunk/LayoutTests/js/regress/scoped-arguments-possibly-overridden-length.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/scoped-arguments-possibly-overridden-length.html	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/script-tests/direct-arguments-length.js (0 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/direct-arguments-length.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/direct-arguments-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,14 @@
+(function() {
+    var args = (function() {
+        return arguments;
+    })(1, 2, 3, 4, 5);
+    
+    var array = [args, [1, 2, 3]];
+    
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += array[i % array.length].length;
+    
+    if (result != 4000000)
+        throw "Error: bad result: " + result;
+})();

Added: trunk/LayoutTests/js/regress/script-tests/direct-arguments-overridden-length.js (0 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/direct-arguments-overridden-length.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/direct-arguments-overridden-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,16 @@
+(function() {
+    var args = (function() {
+        var result = arguments;
+        result.length = 6;
+        return result;
+    })(1, 2, 3, 4, 5);
+    
+    var array = [args, [1, 2, 3]];
+    
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += array[i % array.length].length;
+    
+    if (result != 4500000)
+        throw "Error: bad result: " + result;
+})();

Added: trunk/LayoutTests/js/regress/script-tests/direct-arguments-possibly-overridden-length.js (0 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/direct-arguments-possibly-overridden-length.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/direct-arguments-possibly-overridden-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,20 @@
+(function() {
+    var args1 = (function() {
+        return arguments;
+    })(1, 2, 3);
+    
+    var args2 = (function() {
+        var result = arguments;
+        result.length = 6;
+        return result;
+    })(1, 2, 3, 4, 5);
+    
+    var array = [args1, args2];
+    
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += array[i % array.length].length;
+    
+    if (result != 4500000)
+        throw "Error: bad result: " + result;
+})();

Modified: trunk/LayoutTests/js/regress/script-tests/put-by-id-transition-with-indexing-header.js (199239 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/put-by-id-transition-with-indexing-header.js	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/LayoutTests/js/regress/script-tests/put-by-id-transition-with-indexing-header.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -3,7 +3,7 @@
         return {};
     };
     
-    for (var i = 0; i < 1000; ++i) {
+    for (var i = 0; i < 300; ++i) {
         var o;
         var n = 100;
         for (var j = 0; j < n; ++j) {

Added: trunk/LayoutTests/js/regress/script-tests/scoped-arguments-length.js (0 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/scoped-arguments-length.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/scoped-arguments-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,20 @@
+(function() {
+    var args = (function(a) {
+        (function() {
+            a++;
+        })();
+        return arguments;
+    })(1, 2, 3, 4, 5);
+    
+    if (args[0] != 2)
+        throw "Error: bad args: " + args;
+    
+    var array = [args, [1, 2, 3]];
+    
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += array[i % array.length].length;
+    
+    if (result != 4000000)
+        throw "Error: bad result: " + result;
+})();

Added: trunk/LayoutTests/js/regress/script-tests/scoped-arguments-overridden-length.js (0 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/scoped-arguments-overridden-length.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/scoped-arguments-overridden-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,22 @@
+(function() {
+    var args = (function(a) {
+        (function() {
+            a++;
+        })();
+        var result = arguments;
+        result.length = 6;
+        return result;
+    })(1, 2, 3, 4, 5);
+    
+    if (args[0] != 2)
+        throw "Error: bad args: " + args;
+    
+    var array = [args, [1, 2, 3]];
+    
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += array[i % array.length].length;
+    
+    if (result != 4500000)
+        throw "Error: bad result: " + result;
+})();

Added: trunk/LayoutTests/js/regress/script-tests/scoped-arguments-possibly-overridden-length.js (0 => 199240)


--- trunk/LayoutTests/js/regress/script-tests/scoped-arguments-possibly-overridden-length.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/scoped-arguments-possibly-overridden-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,32 @@
+(function() {
+    var args1 = (function(a) {
+        (function() {
+            a++;
+        })();
+        return arguments;
+    })(1, 2, 3);
+    
+    if (args1[0] != 2)
+        throw "Error: bad args1: " + args1;
+    
+    var args2 = (function(a) {
+        (function() {
+            a++;
+        })();
+        var result = arguments;
+        result.length = 6;
+        return result;
+    })(1, 2, 3, 4, 5);
+    
+    if (args2[0] != 2)
+        throw "Error: bad args2: " + args2;
+    
+    var array = [args1, args2];
+    
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += array[i % array.length].length;
+    
+    if (result != 4500000)
+        throw "Error: bad result: " + result;
+})();

Modified: trunk/Source/_javascript_Core/ChangeLog (199239 => 199240)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-08 19:37:04 UTC (rev 199240)
@@ -1,3 +1,44 @@
+2016-04-08  Filip Pizlo  <[email protected]>
+
+        Add IC support for arguments.length
+        https://bugs.webkit.org/show_bug.cgi?id=156389
+
+        Reviewed by Geoffrey Garen.
+        
+        This adds support for caching accesses to arguments.length for both DirectArguments and
+        ScopedArguments. In strict mode, we already cached these accesses since they were just
+        normal properties.
+
+        Amazingly, we also already supported caching of overridden arguments.length in both
+        DirectArguments and ScopedArguments. This is because when you override, the property gets
+        materialized as a normal JS property and the structure is changed.
+        
+        This patch painstakingly preserves our previous caching of overridden length while
+        introducing caching of non-overridden length (i.e. the common case). In fact, we even cache
+        the case where it could either be overridden or not, since we just end up with an AccessCase
+        for each and they cascade to each other.
+
+        This is a >3x speed-up on microbenchmarks that do arguments.length in a polymorphic context.
+        Entirely monomorphic accesses were already handled by the DFG.
+
+        * bytecode/PolymorphicAccess.cpp:
+        (JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
+        (JSC::AccessCase::guardedByStructureCheck):
+        (JSC::AccessCase::generateWithGuard):
+        (JSC::AccessCase::generate):
+        (WTF::printInternal):
+        * bytecode/PolymorphicAccess.h:
+        * jit/ICStats.h:
+        * jit/JITOperations.cpp:
+        * jit/Repatch.cpp:
+        (JSC::tryCacheGetByID):
+        (JSC::tryCachePutByID):
+        (JSC::tryRepatchIn):
+        * tests/stress/direct-arguments-override-length-then-access-normal-length.js: Added.
+        (args):
+        (foo):
+        (result.foo):
+
 2016-04-08  Benjamin Poulain  <[email protected]>
 
         UInt32ToNumber should have an Int52 path

Modified: trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp (199239 => 199240)


--- trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp	2016-04-08 19:37:04 UTC (rev 199240)
@@ -31,11 +31,13 @@
 #include "BinarySwitch.h"
 #include "CCallHelpers.h"
 #include "CodeBlock.h"
+#include "DirectArguments.h"
 #include "GetterSetter.h"
 #include "Heap.h"
 #include "JITOperations.h"
 #include "JSCInlines.h"
 #include "LinkBuffer.h"
+#include "ScopedArguments.h"
 #include "ScratchRegisterAllocator.h"
 #include "StructureStubClearingWatchpoint.h"
 #include "StructureStubInfo.h"
@@ -81,6 +83,7 @@
             RELEASE_ASSERT(JITCode::isOptimizingJIT(jit->codeBlock()->jitType()));
 
         m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator->usedRegisters());
+        m_liveRegistersForCall.merge(extra);
         m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForJSCall());
         m_liveRegistersForCall.merge(extra);
     }
@@ -395,6 +398,8 @@
     case MegamorphicLoad:
     case ArrayLength:
     case StringLength:
+    case DirectArgumentsLength:
+    case ScopedArgumentsLength:
         return false;
     default:
         return true;
@@ -522,6 +527,46 @@
         break;
     }
         
+    case DirectArgumentsLength: {
+        ASSERT(!viaProxy());
+        fallThrough.append(
+            jit.branch8(
+                CCallHelpers::NotEqual,
+                CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()),
+                CCallHelpers::TrustedImm32(DirectArgumentsType)));
+
+        fallThrough.append(
+            jit.branchTestPtr(
+                CCallHelpers::NonZero,
+                CCallHelpers::Address(baseGPR, DirectArguments::offsetOfOverrides())));
+        jit.load32(
+            CCallHelpers::Address(baseGPR, DirectArguments::offsetOfLength()),
+            valueRegs.payloadGPR());
+        jit.boxInt32(valueRegs.payloadGPR(), valueRegs, CCallHelpers::DoNotHaveTagRegisters);
+        state.succeed();
+        return;
+    }
+        
+    case ScopedArgumentsLength: {
+        ASSERT(!viaProxy());
+        fallThrough.append(
+            jit.branch8(
+                CCallHelpers::NotEqual,
+                CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()),
+                CCallHelpers::TrustedImm32(ScopedArgumentsType)));
+
+        fallThrough.append(
+            jit.branchTest8(
+                CCallHelpers::NonZero,
+                CCallHelpers::Address(baseGPR, ScopedArguments::offsetOfOverrodeThings())));
+        jit.load32(
+            CCallHelpers::Address(baseGPR, ScopedArguments::offsetOfTotalLength()),
+            valueRegs.payloadGPR());
+        jit.boxInt32(valueRegs.payloadGPR(), valueRegs, CCallHelpers::DoNotHaveTagRegisters);
+        state.succeed();
+        return;
+    }
+        
     case MegamorphicLoad: {
         UniquedStringImpl* key = ident.impl();
         unsigned hash = IdentifierRepHash::hash(key);
@@ -1036,7 +1081,7 @@
     }
 
     case Transition: {
-        // AccessCase::transition() should have returned null.
+        // AccessCase::transition() should have returned null if this wasn't true.
         RELEASE_ASSERT(GPRInfo::numberOfRegisters >= 6 || !structure()->outOfLineCapacity() || structure()->outOfLineCapacity() == newStructure()->outOfLineCapacity());
 
         if (InferredType* type = newStructure()->inferredTypeFor(ident.impl())) {
@@ -1257,7 +1302,7 @@
         state.succeed();
         return;
     }
-
+        
     case IntrinsicGetter: {
         RELEASE_ASSERT(isValidOffset(offset()));
 
@@ -1273,11 +1318,13 @@
         emitIntrinsicGetter(state);
         return;
     }
-    
+
+    case DirectArgumentsLength:
+    case ScopedArgumentsLength:
     case MegamorphicLoad:
-        // These need to be handled by generateWithGuard(), since the guard is part of the megamorphic load
-        // algorithm. We can be sure that nobody will call generate() directly for MegamorphicLoad since
-        // MegamorphicLoad is not guarded by a structure check.
+        // These need to be handled by generateWithGuard(), since the guard is part of the
+        // algorithm. We can be sure that nobody will call generate() directly for these since they
+        // are not guarded by structure checks.
         RELEASE_ASSERT_NOT_REACHED();
     }
     
@@ -1679,6 +1726,12 @@
     case AccessCase::StringLength:
         out.print("StringLength");
         return;
+    case AccessCase::DirectArgumentsLength:
+        out.print("DirectArgumentsLength");
+        return;
+    case AccessCase::ScopedArgumentsLength:
+        out.print("ScopedArgumentsLength");
+        return;
     }
 
     RELEASE_ASSERT_NOT_REACHED();

Modified: trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h (199239 => 199240)


--- trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h	2016-04-08 19:37:04 UTC (rev 199240)
@@ -68,7 +68,9 @@
         InHit,
         InMiss,
         ArrayLength,
-        StringLength
+        StringLength,
+        DirectArgumentsLength,
+        ScopedArgumentsLength
     };
 
     static std::unique_ptr<AccessCase> tryGet(

Modified: trunk/Source/_javascript_Core/jit/ICStats.h (199239 => 199240)


--- trunk/Source/_javascript_Core/jit/ICStats.h	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/Source/_javascript_Core/jit/ICStats.h	2016-04-08 19:37:04 UTC (rev 199240)
@@ -40,6 +40,11 @@
 
 #define FOR_EACH_ICEVENT_KIND(macro) \
     macro(InvalidKind) \
+    macro(GetByIdAddAccessCase) \
+    macro(GetByIdReplaceWithJump) \
+    macro(GetByIdSelfPatch) \
+    macro(InAddAccessCase) \
+    macro(InReplaceWithJump) \
     macro(OperationGetById) \
     macro(OperationGetByIdGeneric) \
     macro(OperationGetByIdBuildList) \
@@ -58,7 +63,10 @@
     macro(OperationPutByIdStrictBuildList) \
     macro(OperationPutByIdNonStrictBuildList) \
     macro(OperationPutByIdDirectStrictBuildList) \
-    macro(OperationPutByIdDirectNonStrictBuildList)
+    macro(OperationPutByIdDirectNonStrictBuildList) \
+    macro(PutByIdAddAccessCase) \
+    macro(PutByIdReplaceWithJump) \
+    macro(PutByIdSelfPatch)
 
 class ICEvent {
 public:

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (199239 => 199240)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2016-04-08 19:37:04 UTC (rev 199240)
@@ -188,6 +188,8 @@
 
 EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -203,6 +205,8 @@
 
 EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -215,6 +219,8 @@
 
 EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     Identifier ident = Identifier::fromUid(vm, uid);
@@ -232,6 +238,8 @@
 
 EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -257,6 +265,8 @@
 
 EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -274,6 +284,8 @@
 
 EncodedJSValue JIT_OPERATION operationGenericIn(ExecState* exec, JSCell* base, EncodedJSValue key)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
@@ -282,6 +294,8 @@
 
 void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -297,6 +311,8 @@
 
 void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -311,6 +327,8 @@
 
 void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -325,6 +343,8 @@
 
 void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -339,6 +359,8 @@
 
 void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -362,6 +384,8 @@
 
 void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -385,6 +409,8 @@
 
 void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
@@ -408,6 +434,8 @@
 
 void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (199239 => 199240)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2016-04-08 18:55:27 UTC (rev 199239)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2016-04-08 19:37:04 UTC (rev 199240)
@@ -33,14 +33,17 @@
 #include "CallFrameShuffler.h"
 #include "DFGOperations.h"
 #include "DFGSpeculativeJIT.h"
+#include "DirectArguments.h"
 #include "FTLThunks.h"
 #include "GCAwareJITStubRoutine.h"
 #include "GetterSetter.h"
+#include "ICStats.h"
 #include "JIT.h"
 #include "JITInlines.h"
 #include "LinkBuffer.h"
 #include "JSCInlines.h"
 #include "PolymorphicAccess.h"
+#include "ScopedArguments.h"
 #include "ScratchRegisterAllocator.h"
 #include "StackAlignment.h"
 #include "StructureRareDataInlines.h"
@@ -241,11 +244,24 @@
 
     std::unique_ptr<AccessCase> newCase;
 
-    if (isJSArray(baseValue) && propertyName == exec->propertyNames().length)
-        newCase = AccessCase::getLength(vm, codeBlock, AccessCase::ArrayLength);
-    else if (isJSString(baseValue) && propertyName == exec->propertyNames().length)
-        newCase = AccessCase::getLength(vm, codeBlock, AccessCase::StringLength);
-    else {
+    if (propertyName == vm.propertyNames->length) {
+        if (isJSArray(baseValue))
+            newCase = AccessCase::getLength(vm, codeBlock, AccessCase::ArrayLength);
+        else if (isJSString(baseValue))
+            newCase = AccessCase::getLength(vm, codeBlock, AccessCase::StringLength);
+        else if (DirectArguments* arguments = jsDynamicCast<DirectArguments*>(baseValue)) {
+            // If there were overrides, then we can handle this as a normal property load! Guarding
+            // this with such a check enables us to add an IC case for that load if needed.
+            if (!arguments->overrodeThings())
+                newCase = AccessCase::getLength(vm, codeBlock, AccessCase::DirectArgumentsLength);
+        } else if (ScopedArguments* arguments = jsDynamicCast<ScopedArguments*>(baseValue)) {
+            // Ditto.
+            if (!arguments->overrodeThings())
+                newCase = AccessCase::getLength(vm, codeBlock, AccessCase::ScopedArgumentsLength);
+        }
+    }
+    
+    if (!newCase) {
         if (!slot.isCacheable() && !slot.isUnset())
             return GiveUpOnCache;
 
@@ -275,6 +291,7 @@
             && action == AttemptToCache
             && !structure->needImpurePropertyWatchpoint()
             && !loadTargetFromProxy) {
+            LOG_IC((ICEvent::GetByIdSelfPatch, structure->classInfo(), propertyName));
             structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
             repatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), appropriateOptimizingGetByIdFunction(kind), true);
             stubInfo.initGetByIdSelf(codeBlock, structure, slot.cachedOffset());
@@ -343,6 +360,8 @@
         }
     }
 
+    LOG_IC((ICEvent::GetByIdAddAccessCase, baseValue.classInfoOrNull(), propertyName));
+
     AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, propertyName, WTFMove(newCase));
 
     if (result.gaveUp())
@@ -350,6 +369,8 @@
     if (result.madeNoChanges())
         return RetryCacheLater;
     
+    LOG_IC((ICEvent::GetByIdReplaceWithJump, baseValue.classInfoOrNull(), propertyName));
+
     RELEASE_ASSERT(result.code());
     replaceWithJump(stubInfo, result.code());
     
@@ -416,7 +437,9 @@
                 && MacroAssembler::isPtrAlignedAddressOffset(maxOffsetRelativeToBase(slot.cachedOffset()))
                 && !structure->needImpurePropertyWatchpoint()
                 && !structure->inferredTypeFor(ident.impl())) {
-
+                
+                LOG_IC((ICEvent::PutByIdSelfPatch, structure->classInfo(), ident));
+                
                 repatchByIdSelfAccess(
                     codeBlock, stubInfo, structure, slot.cachedOffset(),
                     appropriateOptimizingPutByIdFunction(slot, putKind), false);
@@ -487,6 +510,8 @@
         }
     }
 
+    LOG_IC((ICEvent::PutByIdAddAccessCase, structure->classInfo(), ident));
+    
     AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
     
     if (result.gaveUp())
@@ -494,6 +519,8 @@
     if (result.madeNoChanges())
         return RetryCacheLater;
 
+    LOG_IC((ICEvent::PutByIdReplaceWithJump, structure->classInfo(), ident));
+
     RELEASE_ASSERT(result.code());
     resetPutByIDCheckAndLoad(stubInfo);
     MacroAssembler::repatchJump(
@@ -544,6 +571,8 @@
     if (!conditionSet.isValid())
         return GiveUpOnCache;
 
+    LOG_IC((ICEvent::InAddAccessCase, structure->classInfo(), ident));
+
     std::unique_ptr<AccessCase> newCase = AccessCase::in(
         vm, codeBlock, wasFound ? AccessCase::InHit : AccessCase::InMiss, structure, conditionSet);
 
@@ -553,6 +582,8 @@
     if (result.madeNoChanges())
         return RetryCacheLater;
 
+    LOG_IC((ICEvent::InReplaceWithJump, structure->classInfo(), ident));
+
     RELEASE_ASSERT(result.code());
     MacroAssembler::repatchJump(
         stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump),

Added: trunk/Source/_javascript_Core/tests/stress/direct-arguments-override-length-then-access-normal-length.js (0 => 199240)


--- trunk/Source/_javascript_Core/tests/stress/direct-arguments-override-length-then-access-normal-length.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/direct-arguments-override-length-then-access-normal-length.js	2016-04-08 19:37:04 UTC (rev 199240)
@@ -0,0 +1,25 @@
+(function() {
+    var args = (function() {
+        var result = arguments;
+        result.length = 6;
+        return result;
+    })(1, 2, 3, 4, 5);
+    
+    var array = [args, [1, 2, 3]];
+    
+    function foo(thing) {
+        return thing.length;
+    }
+    noInline(foo);
+    
+    var result = 0;
+    for (var i = 0; i < 10000; ++i)
+        result += foo(array[i % array.length]);
+    
+    if (result != 45000)
+        throw "Error: bad result: " + result;
+    
+    var result = foo((function() { return arguments; })(1, 2, 3, 4));
+    if (result != 4)
+        throw "Error: bad result: " + result;
+})();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to