Bug 139533

Summary: REGRESSION: Use of undefined CallFrame::ScopeChain value
Product: WebKit Reporter: Michael Saboff <msaboff>
Component: JavaScriptCoreAssignee: Michael Saboff <msaboff>
Status: RESOLVED FIXED    
Severity: Normal CC: clopez, ggaren, mark.lam
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
Attachments:
Description Flags
Patch mark.lam: review+

Michael Saboff
Reported 2014-12-11 00:10:04 PST
The CallFrame ScopeChain slot is still being read and written, even though the JSScope* value is now being stored in an allocated register. When the DFG inlines functions and then one of those inlined functions OSR exits, the ScopeChain slots for the callee's that were inlined will contain whatever values are in memory. The memory for the ScopeChain slots will contain values from the registers allocated by the DFG for the main and inlined functions. The problem is that there is some other residual code elsewhere that assumes that the scope slot of the header contains valid and appropriate JSScope* values. Currently the main code paths that read and write the ScopeChain slot in the CallFrame header and the code paths for making calls. They are still copying from the caller’s scope slot to the callee’s scope slot. The DFG doesn’t know anything special about the scope slots. The fix is to eliminate all the vestige code that reads / writes the old scope slot in the header and then get rid of the space in the header. <rdar://problem/19194440>
Attachments
Patch (28.47 KB, patch)
2014-12-11 01:06 PST, Michael Saboff
mark.lam: review+
Michael Saboff
Comment 1 2014-12-11 01:06:11 PST
Mark Lam
Comment 2 2014-12-11 06:50:53 PST
Comment on attachment 243109 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=243109&action=review r=me with suggested cleanup in ChangeLog and CallFrame.h. > Source/JavaScriptCore/ChangeLog:13 > + Removed CallFrame::scope() and CallFrame::setScope() and eliminated or changed > + all usages of these funcitons. In some cases the scope is passed in or determined > + another way. In some cases the scope is used to calculate other values. Lastly > + were places where these functions where used that are no longer needed. For > + example when making a call, the caller's ScopeChain was copied to the callee's > + ScopeChain. I think it’s implicitly stated here, but can you please say it explicitly that though you are removing the CallFrame scope getter/setter functions: 1. the ScopeChain slot still exists in the CallFrame 2. it just won’t be used anymore 3. it’ll be removed later Did I understand this correctly? > Source/JavaScriptCore/interpreter/CallFrame.h:191 > + ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, JSScope*, Why not remove the JSScope* arg altogether? > Source/JavaScriptCore/jit/JITOpcodes32_64.cpp:905 > + callOperation(operationCreateActivation, regT0, 0); It seems wrong to me that we always pass a literal constant 0 for the offset of activation register. Either: 1. it is contractually fixed to be constant 0 and we don’t need to pass it, or 2. we should “compute” the value. But I understand that this is pre-existing code, and can be cleaned up in a separate patch. > Source/JavaScriptCore/jit/JITOpcodes.cpp:676 > + callOperation(operationCreateActivation, regT0, 0); Ditto.
Michael Saboff
Comment 3 2014-12-11 07:44:02 PST
(In reply to comment #2) > Comment on attachment 243109 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=243109&action=review > > r=me with suggested cleanup in ChangeLog and CallFrame.h. > > > Source/JavaScriptCore/ChangeLog:13 > > + Removed CallFrame::scope() and CallFrame::setScope() and eliminated or changed > > + all usages of these funcitons. In some cases the scope is passed in or determined > > + another way. In some cases the scope is used to calculate other values. Lastly > > + were places where these functions where used that are no longer needed. For > > + example when making a call, the caller's ScopeChain was copied to the callee's > > + ScopeChain. > > I think it’s implicitly stated here, but can you please say it explicitly > that though you are removing the CallFrame scope getter/setter functions: > 1. the ScopeChain slot still exists in the CallFrame > 2. it just won’t be used anymore > 3. it’ll be removed later > > Did I understand this correctly? You understand correctly and I'll add appropriate comments to the ChangeLog. > > Source/JavaScriptCore/interpreter/CallFrame.h:191 > > + ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, JSScope*, > > Why not remove the JSScope* arg altogether? Will do. > > Source/JavaScriptCore/jit/JITOpcodes32_64.cpp:905 > > + callOperation(operationCreateActivation, regT0, 0); > > It seems wrong to me that we always pass a literal constant 0 for the offset > of activation register. Either: > 1. it is contractually fixed to be constant 0 and we don’t need to pass it, > or > 2. we should “compute” the value. > > But I understand that this is pre-existing code, and can be cleaned up in a > separate patch. > > > Source/JavaScriptCore/jit/JITOpcodes.cpp:676 > > + callOperation(operationCreateActivation, regT0, 0); > > Ditto. The literal 0 in these two locations are existing. The DFG computes a value, but the baseline always uses 0. This appears to be by design.
Michael Saboff
Comment 4 2014-12-11 07:52:49 PST
(In reply to comment #3) > > > Source/JavaScriptCore/interpreter/CallFrame.h:191 > > > + ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, JSScope*, > > > > Why not remove the JSScope* arg altogether? init() was dead code, so I deleted the whole function.
Michael Saboff
Comment 5 2014-12-11 08:40:52 PST
Carlos Alberto Lopez Perez
Comment 6 2014-12-11 09:08:56 PST
Mark Lam
Comment 7 2014-12-11 09:11:58 PST
(In reply to comment #4) > init() was dead code, so I deleted the whole function. init() is still in use buy JSGlobalObject.cpp to create the globalExec. This broke the build. I restored CallFrame::init() minus the JSScope* arg, and also removed the arg from the caller. Build fix landed in r177149: <http://trac.webkit.org/r177149>.
Carlos Alberto Lopez Perez
Comment 8 2014-12-11 09:40:36 PST
(In reply to comment #7) > (In reply to comment #4) > > init() was dead code, so I deleted the whole function. > > init() is still in use buy JSGlobalObject.cpp to create the globalExec. > This broke the build. I restored CallFrame::init() minus the JSScope* arg, > and also removed the arg from the caller. > > Build fix landed in r177149: <http://trac.webkit.org/r177149>. Worked :) Thanks!
Michael Saboff
Comment 9 2014-12-11 09:42:02 PST
(In reply to comment #7) > (In reply to comment #4) > > init() was dead code, so I deleted the whole function. > > init() is still in use buy JSGlobalObject.cpp to create the globalExec. > This broke the build. I restored CallFrame::init() minus the JSScope* arg, > and also removed the arg from the caller. > > Build fix landed in r177149: <http://trac.webkit.org/r177149>. Thanks. My bad.
Geoffrey Garen
Comment 10 2014-12-11 14:23:40 PST
This patch really should not have been r+ed without a regression test. Michael, please write a regression test.
Mark Lam
Comment 11 2014-12-11 18:50:27 PST
(In reply to comment #10) > This patch really should not have been r+ed without a regression test. > Michael, please write a regression test. To follow up, Michael has added the regression test in http://trac.webkit.org/changeset/177203.
Note You need to log in before you can comment on or make changes to this bug.