Ignore:
Timestamp:
Mar 12, 2014, 6:50:41 PM (11 years ago)
Author:
[email protected]
Message:
ASSERTION FAILED: node->op() == Phi
node->op() == SetArgument

https://bugs.webkit.org/show_bug.cgi?id=130069

Reviewed by Geoffrey Garen.

This was a great assertion, and it represents our strictest interpretation of the rules of
our intermediate representation. However, fixing DCE to actually preserve the relevant
property would be hard, and it wouldn't have an observable effect right now because nobody
actually uses the propery of CPS that this assertion is checking for.

In particular, we do always require, and rely on, the fact that non-captured variables
have variablesAtTail refer to the last interesting use of the variable: a SetLocal if the
block assigns to the variable, a GetLocal if it only reads from it, and a Flush,
PhantomLocal, or Phi otherwise. We do preserve this property successfully and DCE was not
broken in this regard. But, in the strictest sense, CPS also means that for captured
variables, variablesAtTail also continues to point to the last relevant use of the
variable. In particular, if there are multiple GetLocals, then it should point to the last
one. This is hard for DCE to preserve. Also, nobody relies on variablesAtTail for captured
variables, except to check the VariableAccessData; but in that case, we don't really need
the *last* relevant use of the variable - any node that mentions the same variable will do
just fine.

So, this change loosens the assertion and adds a detailed FIXME describing what we would
have to do if we wanted to preserve the more strict property.

This also makes changes to various debug printing paths so that validation doesn't crash
during graph dump. This also adds tests for the interesting cases of DCE failing to
preserve CPS in the strictest sense. This also attempts to win the record for longest test
name.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::hashAsStringIfPossible):
(JSC::CodeBlock::dumpAssumingJITType):

  • bytecode/CodeBlock.h:
  • bytecode/CodeOrigin.cpp:

(JSC::InlineCallFrame::hashAsStringIfPossible):
(JSC::InlineCallFrame::dumpBriefFunctionInformation):

  • bytecode/CodeOrigin.h:
  • dfg/DFGCPSRethreadingPhase.cpp:

(JSC::DFG::CPSRethreadingPhase::run):

  • dfg/DFGDCEPhase.cpp:

(JSC::DFG::DCEPhase::cleanVariables):

  • dfg/DFGInPlaceAbstractState.cpp:

(JSC::DFG::InPlaceAbstractState::mergeStateAtTail):

  • runtime/FunctionExecutableDump.cpp:

(JSC::FunctionExecutableDump::dump):

  • tests/stress/dead-access-to-captured-variable-preceded-by-a-live-store-in-function-with-multiple-basic-blocks.js: Added.

(foo):

  • tests/stress/dead-access-to-captured-variable-preceded-by-a-live-store.js: Added.

(foo):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp

    r164229 r165522  
    11/*
    2  * Copyright (C) 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    260260            if (node->op() == GetLocal) {
    261261                node = node->child1().node();
    262                 ASSERT(node->op() == Phi || node->op() == SetArgument);
     262               
     263                // FIXME: In the case that the variable is captured, we really want to be able
     264                // to replace the variable-at-tail with the last use of the variable in the same
     265                // way that CPS rethreading would do. The child of the GetLocal isn't necessarily
     266                // the same as what CPS rethreading would do. For example, we may have:
     267                //
     268                // a: SetLocal(...) // live
     269                // b: GetLocal(@a) // live
     270                // c: GetLocal(@a) // dead
     271                //
     272                // When killing @c, the code below will set the variable-at-tail to @a, while CPS
     273                // rethreading would have set @b. This is a benign bug, since all clients of CPS
     274                // only use the variable-at-tail of captured variables to get the
     275                // VariableAccessData and observe that it is in fact captured. But, this feels
     276                // like it could cause bugs in the future.
     277                //
     278                // It's tempting to just dethread and then invoke CPS rethreading, but CPS
     279                // rethreading fails to preserve exact ref-counts. So we would need a fixpoint.
     280                // It's probably the case that this fixpoint will be guaranteed to converge after
     281                // the second iteration (i.e. the second run of DCE will not kill anything and so
     282                // will not need to dethread), but for now the safest approach is probably just to
     283                // allow for this tiny bit of sloppiness.
     284                //
     285                // Another possible solution would be to simply say that DCE dethreads but then
     286                // we never rethread before going to the backend. That feels intuitively right
     287                // because it's unlikely that any of the phases after DCE in the backend rely on
     288                // ThreadedCPS.
     289                //
     290                // https://bugs.webkit.org/show_bug.cgi?id=130115
     291                ASSERT(
     292                    node->op() == Phi || node->op() == SetArgument
     293                    || node->variableAccessData()->isCaptured());
     294               
    263295                if (node->shouldGenerate()) {
    264296                    variables[i] = node;
Note: See TracChangeset for help on using the changeset viewer.