blob: f30cc360b4c3774ed681f0aebee1c0ed5ad493db [file] [log] [blame]
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "DFGMayExit.h"
#if ENABLE(DFG_JIT)
#include "DFGAtTailAbstractState.h"
#include "DFGNode.h"
#include "DFGNullAbstractState.h"
#include "JSCJSValueInlines.h"
namespace JSC { namespace DFG {
namespace {
template<typename StateType>
ExitMode mayExitImpl(Graph& graph, Node* node, StateType& state)
{
ExitMode result = DoesNotExit;
switch (node->op()) {
// This is a carefully curated list of nodes that definitely do not exit. We try to be very
// conservative when maintaining this list, because adding new node types to it doesn't
// generally make things a lot better but it might introduce subtle bugs.
case SetArgumentDefinitely:
case SetArgumentMaybe:
case JSConstant:
case DoubleConstant:
case LazyJSConstant:
case Int52Constant:
case MovHint:
case InitializeEntrypointArguments:
case SetLocal:
case Flush:
case Phantom:
case Check:
case CheckVarargs:
case Identity:
case IdentityWithProfile:
case GetLocal:
case LoopHint:
case Phi:
case Upsilon:
case ExitOK:
case BottomValue:
case PutHint:
case PhantomNewObject:
case PhantomNewInternalFieldObject:
case PutStack:
case KillStack:
case GetStack:
case GetCallee:
case SetCallee:
case GetArgumentCountIncludingThis:
case SetArgumentCountIncludingThis:
case GetRestLength:
case GetScope:
case PhantomLocal:
case CountExecution:
case SuperSamplerBegin:
case SuperSamplerEnd:
case Jump:
case EntrySwitch:
case Branch:
case Unreachable:
case DoubleRep:
case Int52Rep:
case ValueRep:
case ExtractOSREntryLocal:
case ExtractCatchLocal:
case ClearCatchLocals:
case ToBoolean:
case LogicalNot:
case NotifyWrite:
case PutStructure:
case StoreBarrier:
case FencedStoreBarrier:
case PutByOffset:
case PutClosureVar:
case PutInternalField:
case RecordRegExpCachedResult:
case NukeStructureAndSetButterfly:
case FilterCallLinkStatus:
case FilterGetByStatus:
case FilterPutByStatus:
case FilterInByStatus:
case FilterDeleteByStatus:
case FilterCheckPrivateBrandStatus:
case FilterSetPrivateBrandStatus:
case EnumeratorNextExtractMode:
case EnumeratorNextExtractIndex:
break;
case EnumeratorNextUpdatePropertyName:
case StrCat:
case Call:
case Construct:
case CallVarargs:
case CallEval:
case ConstructVarargs:
case CallForwardVarargs:
case ConstructForwardVarargs:
case CreateActivation:
case MaterializeCreateActivation:
case MaterializeNewObject:
case MaterializeNewInternalFieldObject:
case NewFunction:
case NewGeneratorFunction:
case NewAsyncFunction:
case NewAsyncGeneratorFunction:
case NewStringObject:
case NewInternalFieldObject:
case NewRegexp:
case ToNumber:
case ToNumeric:
case ToObject:
case RegExpExecNonGlobalOrSticky:
case RegExpMatchFastGlobal:
result = ExitsForExceptions;
break;
case SetRegExpObjectLastIndex:
if (node->ignoreLastIndexIsWritable())
break;
return Exits;
default:
// If in doubt, return true.
return Exits;
}
graph.doToChildren(
node,
[&] (Edge& edge) {
if (state) {
// Ignore the Check flag on the edge. This is important because that flag answers
// the question: "would this edge have had a check if it executed wherever it
// currently resides in control flow?" But when a state is passed, we want to ask a
// different question: "would this edge have a check if it executed wherever this
// state is?" Using the Check flag for this purpose wouldn't even be conservatively
// correct. It would be wrong in both directions.
if (mayHaveTypeCheck(edge.useKind())
&& (state.forNode(edge).m_type & ~typeFilterFor(edge.useKind()))) {
result = Exits;
return;
}
} else {
// FIXME: Maybe this should call mayHaveTypeCheck(edge.useKind()) instead.
// https://bugs.webkit.org/show_bug.cgi?id=148545
if (edge.willHaveCheck()) {
result = Exits;
return;
}
}
switch (edge.useKind()) {
// These are shady because nodes that have these use kinds will typically exit for
// unrelated reasons. For example CompareEq doesn't usually exit, but if it uses
// ObjectUse then it will.
case ObjectUse:
case ObjectOrOtherUse:
result = Exits;
break;
default:
break;
}
});
return result;
}
} // anonymous namespace
ExitMode mayExit(Graph& graph, Node* node)
{
NullAbstractState state;
return mayExitImpl(graph, node, state);
}
ExitMode mayExit(Graph& graph, Node* node, AtTailAbstractState& state)
{
return mayExitImpl(graph, node, state);
}
} } // namespace JSC::DFG
namespace WTF {
using namespace JSC::DFG;
void printInternal(PrintStream& out, ExitMode mode)
{
switch (mode) {
case DoesNotExit:
out.print("DoesNotExit");
return;
case ExitsForExceptions:
out.print("ExitsForExceptions");
return;
case Exits:
out.print("Exits");
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
} // namespace WTF
#endif // ENABLE(DFG_JIT)