Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (164922 => 164923)
--- trunk/Source/_javascript_Core/ChangeLog 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-03-01 19:57:40 UTC (rev 164923)
@@ -1,5 +1,45 @@
2014-02-28 Filip Pizlo <[email protected]>
+ FTL should support PhantomArguments
+ https://bugs.webkit.org/show_bug.cgi?id=113986
+
+ Reviewed by Oliver Hunt.
+
+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments
+ object into the FTL's OSR exit compiler.
+
+ This isn't a speed-up yet, since there is still more to be done to fully support
+ all of the arguments craziness that our varargs benchmarks do.
+
+ * dfg/DFGOSRExitCompiler32_64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit): move the recovery code to DFGOSRExitCompilerCommon.cpp
+ * dfg/DFGOSRExitCompiler64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit): move the recovery code to DFGOSRExitCompilerCommon.cpp
+ * dfg/DFGOSRExitCompilerCommon.cpp:
+ (JSC::DFG::ArgumentsRecoveryGenerator::ArgumentsRecoveryGenerator):
+ (JSC::DFG::ArgumentsRecoveryGenerator::~ArgumentsRecoveryGenerator):
+ (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): this is the common place for the recovery code
+ * dfg/DFGOSRExitCompilerCommon.h:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLExitValue.cpp:
+ (JSC::FTL::ExitValue::dumpInContext):
+ * ftl/FTLExitValue.h:
+ (JSC::FTL::ExitValue::argumentsObjectThatWasNotCreated):
+ (JSC::FTL::ExitValue::isArgumentsObjectThatWasNotCreated):
+ (JSC::FTL::ExitValue::valueFormat):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compilePhantomArguments):
+ (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
+ (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument):
+ * ftl/FTLOSRExitCompiler.cpp:
+ (JSC::FTL::compileStub): Call into the ArgumentsRecoveryGenerator
+ * tests/stress/slightly-more-difficult-to-fold-reflective-arguments-access.js: Added.
+ * tests/stress/trivially-foldable-reflective-arguments-access.js: Added.
+
+2014-02-28 Filip Pizlo <[email protected]>
+
Unreviewed, uncomment some code. It wasn't meant to be commented in the first place.
* dfg/DFGCSEPhase.cpp:
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -393,66 +393,14 @@
// registers.
if (haveArguments) {
- HashSet<InlineCallFrame*, DefaultHash<InlineCallFrame*>::Hash,
- NullableHashTraits<InlineCallFrame*>> didCreateArgumentsObject;
+ ArgumentsRecoveryGenerator argumentsRecovery;
for (size_t index = 0; index < operands.size(); ++index) {
const ValueRecovery& recovery = operands[index];
if (recovery.technique() != ArgumentsThatWereNotCreated)
continue;
- int operand = operands.operandForIndex(index);
- // Find the right inline call frame.
- InlineCallFrame* inlineCallFrame = 0;
- for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame;
- current;
- current = current->caller.inlineCallFrame) {
- if (current->stackOffset >= operand) {
- inlineCallFrame = current;
- break;
- }
- }
-
- if (!m_jit.baselineCodeBlockFor(inlineCallFrame)->usesArguments())
- continue;
- VirtualRegister argumentsRegister = m_jit.baselineArgumentsRegisterFor(inlineCallFrame);
- if (didCreateArgumentsObject.add(inlineCallFrame).isNewEntry) {
- // We know this call frame optimized out an arguments object that
- // the baseline JIT would have created. Do that creation now.
- if (inlineCallFrame) {
- m_jit.setupArgumentsWithExecState(
- AssemblyHelpers::TrustedImmPtr(inlineCallFrame));
- m_jit.move(
- AssemblyHelpers::TrustedImmPtr(
- bitwise_cast<void*>(operationCreateInlinedArguments)),
- GPRInfo::nonArgGPR0);
- } else {
- m_jit.setupArgumentsExecState();
- m_jit.move(
- AssemblyHelpers::TrustedImmPtr(
- bitwise_cast<void*>(operationCreateArguments)),
- GPRInfo::nonArgGPR0);
- }
- m_jit.call(GPRInfo::nonArgGPR0);
- m_jit.store32(
- AssemblyHelpers::TrustedImm32(JSValue::CellTag),
- AssemblyHelpers::tagFor(argumentsRegister));
- m_jit.store32(
- GPRInfo::returnValueGPR,
- AssemblyHelpers::payloadFor(argumentsRegister));
- m_jit.store32(
- AssemblyHelpers::TrustedImm32(JSValue::CellTag),
- AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister)));
- m_jit.store32(
- GPRInfo::returnValueGPR,
- AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister)));
- m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms.
- }
-
- m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0);
- m_jit.store32(
- AssemblyHelpers::TrustedImm32(JSValue::CellTag),
- AssemblyHelpers::tagFor(operand));
- m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand));
+ argumentsRecovery.generateFor(
+ operands.operandForIndex(index), exit.m_codeOrigin, m_jit);
}
}
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -365,50 +365,14 @@
// registers.
if (haveArguments) {
- HashSet<InlineCallFrame*, DefaultHash<InlineCallFrame*>::Hash,
- NullableHashTraits<InlineCallFrame*>> didCreateArgumentsObject;
+ ArgumentsRecoveryGenerator argumentsRecovery;
for (size_t index = 0; index < operands.size(); ++index) {
const ValueRecovery& recovery = operands[index];
if (recovery.technique() != ArgumentsThatWereNotCreated)
continue;
- int operand = operands.operandForIndex(index);
- // Find the right inline call frame.
- InlineCallFrame* inlineCallFrame = 0;
- for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame;
- current;
- current = current->caller.inlineCallFrame) {
- if (current->stackOffset >= operand) {
- inlineCallFrame = current;
- break;
- }
- }
-
- if (!m_jit.baselineCodeBlockFor(inlineCallFrame)->usesArguments())
- continue;
- VirtualRegister argumentsRegister = m_jit.baselineArgumentsRegisterFor(inlineCallFrame);
- if (didCreateArgumentsObject.add(inlineCallFrame).isNewEntry) {
- // We know this call frame optimized out an arguments object that
- // the baseline JIT would have created. Do that creation now.
- if (inlineCallFrame) {
- m_jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT0);
- m_jit.setupArguments(GPRInfo::regT0);
- } else
- m_jit.setupArgumentsExecState();
- m_jit.move(
- AssemblyHelpers::TrustedImmPtr(
- bitwise_cast<void*>(operationCreateArguments)),
- GPRInfo::nonArgGPR0);
- m_jit.call(GPRInfo::nonArgGPR0);
- m_jit.store64(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister));
- m_jit.store64(
- GPRInfo::returnValueGPR,
- AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister)));
- m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms.
- }
-
- m_jit.load64(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0);
- m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
+ argumentsRecovery.generateFor(
+ operands.operandForIndex(index), exit.m_codeOrigin, m_jit);
}
}
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -217,6 +217,89 @@
jit.jump(GPRInfo::regT2);
}
+ArgumentsRecoveryGenerator::ArgumentsRecoveryGenerator() { }
+ArgumentsRecoveryGenerator::~ArgumentsRecoveryGenerator() { }
+
+void ArgumentsRecoveryGenerator::generateFor(
+ int operand, CodeOrigin codeOrigin, CCallHelpers& jit)
+{
+ // Find the right inline call frame.
+ InlineCallFrame* inlineCallFrame = 0;
+ for (InlineCallFrame* current = codeOrigin.inlineCallFrame;
+ current;
+ current = current->caller.inlineCallFrame) {
+ if (current->stackOffset >= operand) {
+ inlineCallFrame = current;
+ break;
+ }
+ }
+
+ if (!jit.baselineCodeBlockFor(inlineCallFrame)->usesArguments())
+ return;
+ VirtualRegister argumentsRegister = jit.baselineArgumentsRegisterFor(inlineCallFrame);
+ if (m_didCreateArgumentsObject.add(inlineCallFrame).isNewEntry) {
+ // We know this call frame optimized out an arguments object that
+ // the baseline JIT would have created. Do that creation now.
+#if USE(JSVALUE64)
+ if (inlineCallFrame) {
+ jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT0);
+ jit.setupArguments(GPRInfo::regT0);
+ } else
+ jit.setupArgumentsExecState();
+ jit.move(
+ AssemblyHelpers::TrustedImmPtr(
+ bitwise_cast<void*>(operationCreateArguments)),
+ GPRInfo::nonArgGPR0);
+ jit.call(GPRInfo::nonArgGPR0);
+ jit.store64(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister));
+ jit.store64(
+ GPRInfo::returnValueGPR,
+ AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister)));
+ jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms.
+#else // USE(JSVALUE64) -> so the 32_64 part
+ if (inlineCallFrame) {
+ jit.setupArgumentsWithExecState(
+ AssemblyHelpers::TrustedImmPtr(inlineCallFrame));
+ jit.move(
+ AssemblyHelpers::TrustedImmPtr(
+ bitwise_cast<void*>(operationCreateInlinedArguments)),
+ GPRInfo::nonArgGPR0);
+ } else {
+ jit.setupArgumentsExecState();
+ jit.move(
+ AssemblyHelpers::TrustedImmPtr(
+ bitwise_cast<void*>(operationCreateArguments)),
+ GPRInfo::nonArgGPR0);
+ }
+ jit.call(GPRInfo::nonArgGPR0);
+ jit.store32(
+ AssemblyHelpers::TrustedImm32(JSValue::CellTag),
+ AssemblyHelpers::tagFor(argumentsRegister));
+ jit.store32(
+ GPRInfo::returnValueGPR,
+ AssemblyHelpers::payloadFor(argumentsRegister));
+ jit.store32(
+ AssemblyHelpers::TrustedImm32(JSValue::CellTag),
+ AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister)));
+ jit.store32(
+ GPRInfo::returnValueGPR,
+ AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister)));
+ jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms.
+#endif // USE(JSVALUE64)
+ }
+
+#if USE(JSVALUE64)
+ jit.load64(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0);
+ jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
+#else // USE(JSVALUE64) -> so the 32_64 part
+ jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0);
+ jit.store32(
+ AssemblyHelpers::TrustedImm32(JSValue::CellTag),
+ AssemblyHelpers::tagFor(operand));
+ jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand));
+#endif // USE(JSVALUE64)
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.h (164922 => 164923)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.h 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.h 2014-03-01 19:57:40 UTC (rev 164923)
@@ -37,6 +37,18 @@
void reifyInlinedCallFrames(CCallHelpers&, const OSRExitBase&);
void adjustAndJumpToTarget(CCallHelpers&, const OSRExitBase&);
+class ArgumentsRecoveryGenerator {
+public:
+ ArgumentsRecoveryGenerator();
+ ~ArgumentsRecoveryGenerator();
+
+ void generateFor(int operand, CodeOrigin, CCallHelpers&);
+
+private:
+ HashSet<InlineCallFrame*, DefaultHash<InlineCallFrame*>::Hash,
+ NullableHashTraits<InlineCallFrame*>> m_didCreateArgumentsObject;
+};
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -140,6 +140,7 @@
case MultiGetByOffset:
case MultiPutByOffset:
case ToPrimitive:
+ case PhantomArguments:
// These are OK.
break;
case PutByIdDirect:
Modified: trunk/Source/_javascript_Core/ftl/FTLExitValue.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/ftl/FTLExitValue.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/ftl/FTLExitValue.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -59,6 +59,9 @@
case ExitValueInJSStackAsDouble:
out.print("InJSStackAsDouble:r", virtualRegister());
return;
+ case ExitValueArgumentsObjectThatWasNotCreated:
+ out.print("ArgumentsObjectThatWasNotCreated");
+ return;
case ExitValueRecovery:
out.print("Recovery(", recoveryOpcode(), ", arg", leftRecoveryArgument(), ", arg", rightRecoveryArgument(), ", ", recoveryFormat(), ")");
return;
Modified: trunk/Source/_javascript_Core/ftl/FTLExitValue.h (164922 => 164923)
--- trunk/Source/_javascript_Core/ftl/FTLExitValue.h 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/ftl/FTLExitValue.h 2014-03-01 19:57:40 UTC (rev 164923)
@@ -51,6 +51,7 @@
ExitValueInJSStackAsInt32,
ExitValueInJSStackAsInt52,
ExitValueInJSStackAsDouble,
+ ExitValueArgumentsObjectThatWasNotCreated,
ExitValueRecovery
};
@@ -118,6 +119,13 @@
return result;
}
+ static ExitValue argumentsObjectThatWasNotCreated()
+ {
+ ExitValue result;
+ result.m_kind = ExitValueArgumentsObjectThatWasNotCreated;
+ return result;
+ }
+
static ExitValue recovery(RecoveryOpcode opcode, unsigned leftArgument, unsigned rightArgument, ValueFormat format)
{
ExitValue result;
@@ -146,6 +154,7 @@
}
bool isConstant() const { return kind() == ExitValueConstant; }
bool isArgument() const { return kind() == ExitValueArgument; }
+ bool isArgumentsObjectThatWasNotCreated() const { return kind() == ExitValueArgumentsObjectThatWasNotCreated; }
bool isRecovery() const { return kind() == ExitValueRecovery; }
ExitArgument exitArgument() const
@@ -213,6 +222,7 @@
case ExitValueDead:
case ExitValueConstant:
case ExitValueInJSStack:
+ case ExitValueArgumentsObjectThatWasNotCreated:
return ValueFormatJSValue;
case ExitValueArgument:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -282,6 +282,9 @@
case WeakJSConstant:
compileWeakJSConstant();
break;
+ case PhantomArguments:
+ compilePhantomArguments();
+ break;
case GetArgument:
compileGetArgument();
break;
@@ -781,6 +784,11 @@
break;
}
}
+
+ void compilePhantomArguments()
+ {
+ setJSValue(m_out.constInt64(JSValue::encode(JSValue())));
+ }
void compileWeakJSConstant()
{
@@ -5519,9 +5527,7 @@
break;
case FlushedArguments:
- // FIXME: implement PhantomArguments.
- // https://bugs.webkit.org/show_bug.cgi?id=113986
- RELEASE_ASSERT_NOT_REACHED();
+ exit.m_values[i] = ExitValue::argumentsObjectThatWasNotCreated();
break;
}
}
@@ -5613,9 +5619,7 @@
exit.m_values[index] = ExitValue::constant(m_graph.valueOfJSConstant(node));
return true;
case PhantomArguments:
- // FIXME: implement PhantomArguments.
- // https://bugs.webkit.org/show_bug.cgi?id=113986
- RELEASE_ASSERT_NOT_REACHED();
+ exit.m_values[index] = ExitValue::argumentsObjectThatWasNotCreated();
return true;
default:
return false;
Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp (164922 => 164923)
--- trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp 2014-03-01 19:42:14 UTC (rev 164922)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp 2014-03-01 19:57:40 UTC (rev 164923)
@@ -146,6 +146,12 @@
jit.load64(AssemblyHelpers::addressFor(value.virtualRegister()), GPRInfo::regT0);
break;
+ case ExitValueArgumentsObjectThatWasNotCreated:
+ // We can't actually recover this yet, but we can make the stack look sane. This is
+ // a prerequisite to running the actual arguments recovery.
+ jit.move(MacroAssembler::TrustedImm64(JSValue::encode(JSValue())), GPRInfo::regT0);
+ break;
+
case ExitValueRecovery:
record->locations[value.rightRecoveryArgument()].restoreInto(
jit, jitCode->stackmaps, registerScratch, GPRInfo::regT1);
@@ -337,6 +343,15 @@
handleExitCounts(jit, exit);
reifyInlinedCallFrames(jit, exit);
+
+ ArgumentsRecoveryGenerator argumentsRecovery;
+ for (unsigned index = exit.m_values.size(); index--;) {
+ if (!exit.m_values[index].isArgumentsObjectThatWasNotCreated())
+ continue;
+ int operand = exit.m_values.operandForIndex(index);
+ argumentsRecovery.generateFor(operand, exit.m_codeOrigin, jit);
+ }
+
adjustAndJumpToTarget(jit, exit);
LinkBuffer patchBuffer(*vm, &jit, codeBlock);
Added: trunk/Source/_javascript_Core/tests/stress/slightly-more-difficult-to-fold-reflective-arguments-access.js (0 => 164923)
--- trunk/Source/_javascript_Core/tests/stress/slightly-more-difficult-to-fold-reflective-arguments-access.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/slightly-more-difficult-to-fold-reflective-arguments-access.js 2014-03-01 19:57:40 UTC (rev 164923)
@@ -0,0 +1,16 @@
+function foo() {
+ var a = arguments;
+ return a[0];
+}
+
+function bar(x) {
+ return foo(x);
+}
+
+noInline(bar);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = bar(42);
+ if (result != 42)
+ throw "Error: bad result: " + result;
+}
Added: trunk/Source/_javascript_Core/tests/stress/trivially-foldable-reflective-arguments-access.js (0 => 164923)
--- trunk/Source/_javascript_Core/tests/stress/trivially-foldable-reflective-arguments-access.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/trivially-foldable-reflective-arguments-access.js 2014-03-01 19:57:40 UTC (rev 164923)
@@ -0,0 +1,15 @@
+function foo() {
+ return arguments[0];
+}
+
+function bar(x) {
+ return foo(x);
+}
+
+noInline(bar);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = bar(42);
+ if (result != 42)
+ throw "Error: bad result: " + result;
+}