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;
+})();