RESOLVED FIXED 113986
FTL should support PhantomArguments
https://bugs.webkit.org/show_bug.cgi?id=113986
Summary FTL should support PhantomArguments
Filip Pizlo
Reported 2013-04-04 18:44:37 PDT
I'll do this after I do OSR.
Attachments
work in progress (20.15 KB, patch)
2014-02-28 15:13 PST, Filip Pizlo
no flags
the patch (20.45 KB, patch)
2014-02-28 15:23 PST, Filip Pizlo
oliver: review+
Filip Pizlo
Comment 1 2014-02-28 15:13:56 PST
Created attachment 225494 [details] work in progress
Filip Pizlo
Comment 2 2014-02-28 15:21:24 PST
(In reply to comment #1) > Created an attachment (id=225494) [details] > work in progress Shockingly, this appears to actually just work.
Filip Pizlo
Comment 3 2014-02-28 15:23:36 PST
Created attachment 225498 [details] the patch
WebKit Commit Bot
Comment 4 2014-02-28 15:26:57 PST
Attachment 225498 [details] did not pass style-queue: ERROR: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp:229: Weird number of spaces at line-start. Are you using a 4-space indent? [whitespace/indent] [3] ERROR: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp:230: Weird number of spaces at line-start. Are you using a 4-space indent? [whitespace/indent] [3] Total errors found: 2 in 10 files If any of these errors are false positives, please file a bug against check-webkit-style.
Filip Pizlo
Comment 5 2014-03-01 11:52:25 PST
Whitehat Security
Comment 6 2014-10-25 19:19:52 PDT
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 7 2014-10-25 19:19:56 PDT
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 8 2014-10-25 19:20:00 PDT
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 9 2014-11-07 07:47:46 PST
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 10 2014-11-07 07:47:50 PST
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 11 2014-11-07 07:47:54 PST
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 12 2014-11-18 13:40:21 PST
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 13 2014-11-18 13:40:25 PST
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Whitehat Security
Comment 14 2014-11-18 13:40:30 PST
Comment on attachment 225498 [details] the patch >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 164889) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,38 @@ >+2014-02-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should support PhantomArguments >+ https://bugs.webkit.org/show_bug.cgi?id=113986 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments >+ object into the FTL's OSR exit compiler. >+ >+ * 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 >+ > 2014-02-28 Oliver Hunt <oliver@apple.com> > > REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -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 @@ void OSRExitCompiler::compileExit(const > // 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); > } > } > >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -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 @@ void adjustAndJumpToTarget(CCallHelpers& > 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) >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (revision 164883) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h (working copy) >@@ -37,6 +37,18 @@ void handleExitCounts(CCallHelpers&, con > 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) >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -140,6 +140,7 @@ inline CapabilityLevel canCompile(Node* > case MultiGetByOffset: > case MultiPutByOffset: > case ToPrimitive: >+ case PhantomArguments: > // These are OK. > break; > case PutByIdDirect: >Index: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -59,6 +59,9 @@ void ExitValue::dumpInContext(PrintStrea > 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; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -51,6 +51,7 @@ enum ExitValueKind { > ExitValueInJSStackAsInt32, > ExitValueInJSStackAsInt52, > ExitValueInJSStackAsDouble, >+ ExitValueArgumentsObjectThatWasNotCreated, > ExitValueRecovery > }; > >@@ -118,6 +119,13 @@ public: > 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 @@ public: > } > 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 @@ public: > case ExitValueDead: > case ExitValueConstant: > case ExitValueInJSStack: >+ case ExitValueArgumentsObjectThatWasNotCreated: > return ValueFormatJSValue; > > case ExitValueArgument: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -282,6 +282,9 @@ private: > case WeakJSConstant: > compileWeakJSConstant(); > break; >+ case PhantomArguments: >+ compilePhantomArguments(); >+ break; > case GetArgument: > compileGetArgument(); > break; >@@ -781,6 +784,11 @@ private: > break; > } > } >+ >+ void compilePhantomArguments() >+ { >+ setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); >+ } > > void compileWeakJSConstant() > { >@@ -5519,9 +5527,7 @@ private: > 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 @@ private: > 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; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 164883) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -146,6 +146,12 @@ static void compileStub( > 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 @@ static void compileStub( > > 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);
Note You need to log in before you can comment on or make changes to this bug.