/*
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DFGSafeToExecute_h
-#define DFGSafeToExecute_h
+#pragma once
#if ENABLE(DFG_JIT)
public:
SafeToExecuteEdge(AbstractStateType& state)
: m_state(state)
- , m_result(true)
{
}
void operator()(Node*, Edge edge)
{
+ m_maySeeEmptyChild |= !!(m_state.forNode(edge).m_type & SpecEmpty);
+
switch (edge.useKind()) {
case UntypedUse:
case Int32Use:
case CellUse:
case CellOrOtherUse:
case ObjectUse:
+ case ArrayUse:
case FunctionUse:
case FinalObjectUse:
case RegExpObjectUse:
+ case ProxyObjectUse:
+ case DerivedArrayUse:
+ case MapObjectUse:
+ case SetObjectUse:
+ case WeakMapObjectUse:
+ case WeakSetObjectUse:
case ObjectOrOtherUse:
case StringIdentUse:
case StringUse:
case StringObjectUse:
case StringOrStringObjectUse:
case NotStringVarUse:
+ case NotSymbolUse:
case NotCellUse:
case OtherUse:
case MiscUse:
- case MachineIntUse:
- case DoubleRepMachineIntUse:
+ case AnyIntUse:
+ case DoubleRepAnyIntUse:
return;
case KnownInt32Use:
- if (m_state.forNode(edge).m_type & ~SpecInt32)
+ if (m_state.forNode(edge).m_type & ~SpecInt32Only)
m_result = false;
return;
}
bool result() const { return m_result; }
+ bool maySeeEmptyChild() const { return m_maySeeEmptyChild; }
private:
AbstractStateType& m_state;
- bool m_result;
+ bool m_result { true };
+ bool m_maySeeEmptyChild { false };
};
// Determines if it's safe to execute a node within the given abstract state. This may
if (!safeToExecuteEdge.result())
return false;
+ if (safeToExecuteEdge.maySeeEmptyChild()) {
+ // We conservatively assume if the empty value flows into a node,
+ // it might not be able to handle it (e.g, crash). In general, the bytecode generator
+ // emits code in such a way that most node types don't need to worry about the empty value
+ // because they will never see it. However, code motion has to consider the empty
+ // value so it does not insert/move nodes to a place where they will crash. E.g, the
+ // type check hoisting phase needs to insert CheckStructureOrEmpty instead of CheckStructure
+ // for hoisted structure checks because it can not guarantee that a particular local is not
+ // the empty value.
+ switch (node->op()) {
+ case CheckNotEmpty:
+ case CheckStructureOrEmpty:
+ break;
+ default:
+ return false;
+ }
+ }
+
// NOTE: This tends to lie when it comes to effectful nodes, because it knows that they aren't going to
// get hoisted anyway.
case Int52Constant:
case LazyJSConstant:
case Identity:
+ case IdentityWithProfile:
case ToThis:
case CreateThis:
case GetCallee:
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
case GetRestLength:
case GetLocal:
case SetLocal:
case Phi:
case Flush:
case PhantomLocal:
- case GetLocalUnlinked:
case SetArgument:
case BitAnd:
case BitOr:
case ArithFloor:
case ArithCeil:
case ArithTrunc:
- case ArithSin:
- case ArithCos:
- case ArithLog:
+ case ArithUnary:
case ValueAdd:
case TryGetById:
case DeleteById:
+ case DeleteByVal:
case GetById:
+ case GetByIdWithThis:
+ case GetByValWithThis:
case GetByIdFlush:
case PutById:
case PutByIdFlush:
+ case PutByIdWithThis:
+ case PutByValWithThis:
case PutByIdDirect:
case PutGetterById:
case PutSetterById:
case PutGetterSetterById:
case PutGetterByVal:
case PutSetterByVal:
+ case DefineDataProperty:
+ case DefineAccessorProperty:
case CheckStructure:
+ case CheckStructureOrEmpty:
case GetExecutable:
case GetButterfly:
+ case CallDOMGetter:
+ case CallDOM:
+ case CheckSubClass:
case CheckArray:
case Arrayify:
case ArrayifyToStructure:
case GetScope:
case SkipScope:
case GetGlobalObject:
+ case GetGlobalThis:
case GetClosureVar:
case PutClosureVar:
case GetGlobalVar:
case GetGlobalLexicalVariable:
case PutGlobalVariable:
- case VarInjectionWatchpoint:
case CheckCell:
case CheckBadCell:
case CheckNotEmpty:
- case CheckIdent:
+ case CheckStringIdent:
case RegExpExec:
case RegExpTest:
case CompareLess:
case CompareLessEq:
case CompareGreater:
case CompareGreaterEq:
+ case CompareBelow:
+ case CompareBelowEq:
case CompareEq:
case CompareStrictEq:
+ case CompareEqPtr:
case Call:
+ case DirectCall:
case TailCallInlinedCaller:
+ case DirectTailCallInlinedCaller:
case Construct:
+ case DirectConstruct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case TailCallForwardVarargsInlinedCaller:
case ConstructVarargs:
case NewArray:
case NewArrayWithSize:
case NewArrayBuffer:
+ case NewArrayWithSpread:
+ case Spread:
case NewRegexp:
- case ProfileWillCall:
- case ProfileDidCall:
case ProfileType:
case ProfileControlFlow:
case CheckTypeInfoFlags:
+ case ParseInt:
case OverridesHasInstance:
case InstanceOf:
case InstanceOfCustom:
- case IsArrayObject:
- case IsJSArray:
- case IsArrayConstructor:
+ case IsEmpty:
case IsUndefined:
case IsBoolean:
case IsNumber:
- case IsString:
case IsObject:
case IsObjectOrNull:
case IsFunction:
- case IsRegExpObject:
+ case IsCellWithType:
+ case IsTypedArrayView:
case TypeOf:
case LogicalNot:
case CallObjectConstructor:
case ToPrimitive:
case ToString:
+ case ToNumber:
+ case ToObject:
+ case NumberToStringWithRadix:
+ case NumberToStringWithValidRadixConstant:
case SetFunctionName:
case StrCat:
case CallStringConstructor:
case NewStringObject:
case MakeRope:
case In:
+ case HasOwnProperty:
+ case PushWithScope:
case CreateActivation:
case CreateDirectArguments:
case CreateScopedArguments:
case CreateClonedArguments:
case GetFromArguments:
+ case GetArgument:
case PutToArguments:
case NewFunction:
case NewGeneratorFunction:
+ case NewAsyncGeneratorFunction:
+ case NewAsyncFunction:
case Jump:
case Branch:
case Switch:
+ case EntrySwitch:
case Return:
case TailCall:
+ case DirectTailCall:
case TailCallVarargs:
case TailCallForwardVarargs:
case Throw:
- case ThrowReferenceError:
+ case ThrowStaticError:
case CountExecution:
+ case SuperSamplerBegin:
+ case SuperSamplerEnd:
case ForceOSRExit:
- case CheckWatchdogTimer:
+ case CPUIntrinsic:
+ case CheckTraps:
case LogShadowChickenPrologue:
case LogShadowChickenTail:
case StringFromCharCode:
case NewTypedArray:
case Unreachable:
case ExtractOSREntryLocal:
+ case ExtractCatchLocal:
case CheckTierUpInLoop:
case CheckTierUpAtReturn:
case CheckTierUpAndOSREnter:
case LoopHint:
- case StoreBarrier:
case InvalidationPoint:
case NotifyWrite:
case CheckInBounds:
case PhantomNewObject:
case PhantomNewFunction:
case PhantomNewGeneratorFunction:
+ case PhantomNewAsyncGeneratorFunction:
+ case PhantomNewAsyncFunction:
case PhantomCreateActivation:
case PutHint:
case CheckStructureImmediate:
case MaterializeNewObject:
case MaterializeCreateActivation:
case PhantomDirectArguments:
+ case PhantomCreateRest:
+ case PhantomSpread:
+ case PhantomNewArrayWithSpread:
case PhantomClonedArguments:
case GetMyArgumentByVal:
case GetMyArgumentByValOutOfBounds:
case ForwardVarargs:
- case CopyRest:
+ case CreateRest:
+ case GetPrototypeOf:
case StringReplace:
+ case StringReplaceRegExp:
case GetRegExpObjectLastIndex:
case SetRegExpObjectLastIndex:
case RecordRegExpCachedResult:
case GetDynamicVar:
case PutDynamicVar:
+ case ResolveScopeForHoistingFuncDeclInEval:
case ResolveScope:
+ case MapHash:
+ case NormalizeMapKey:
+ case StringSlice:
+ case ToLowerCase:
+ case GetMapBucket:
+ case GetMapBucketHead:
+ case GetMapBucketNext:
+ case LoadKeyFromMapBucket:
+ case LoadValueFromMapBucket:
+ case ExtractValueFromWeakMapGet:
+ case WeakMapGet:
+ case AtomicsAdd:
+ case AtomicsAnd:
+ case AtomicsCompareExchange:
+ case AtomicsExchange:
+ case AtomicsLoad:
+ case AtomicsOr:
+ case AtomicsStore:
+ case AtomicsSub:
+ case AtomicsXor:
+ case AtomicsIsLockFree:
+ case InitializeEntrypointArguments:
return true;
+ case ArraySlice:
+ case ArrayIndexOf: {
+ // You could plausibly move this code around as long as you proved the
+ // incoming array base structure is an original array at the hoisted location.
+ // Instead of doing that extra work, we just conservatively return false.
+ return false;
+ }
+
case BottomValue:
// If in doubt, assume that this isn't safe to execute, just because we have no way of
// compiling this node.
return false;
+ case StoreBarrier:
+ case FencedStoreBarrier:
+ case PutStructure:
+ case NukeStructureAndSetButterfly:
+ // We conservatively assume that these cannot be put anywhere, which forces the compiler to
+ // keep them exactly where they were. This is sort of overkill since the clobberize effects
+ // already force these things to be ordered precisely. I'm just not confident enough in my
+ // effect based memory model to rely solely on that right now.
+ return false;
+
case GetByVal:
case GetIndexedPropertyStorage:
case GetArrayLength:
- case ArrayPush:
+ case GetVectorLength:
case ArrayPop:
case StringCharAt:
case StringCharCodeAt:
return node->arrayMode().alreadyChecked(graph, node, state.forNode(node->child1()));
-
+
+ case ArrayPush:
+ return node->arrayMode().alreadyChecked(graph, node, state.forNode(graph.varArgChild(node, 1)));
+
case GetTypedArrayByteOffset:
return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
return node->arrayMode().modeForPut().alreadyChecked(
graph, node, state.forNode(graph.varArgChild(node, 0)));
- case PutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
return state.forNode(node->child1()).m_structure.isSubsetOf(
- StructureSet(node->transition()->previous));
+ RegisteredStructureSet(node->transition()->previous));
case GetByOffset:
case GetGetterSetterByOffset:
PropertyOffset offset = node->storageAccessData().offset;
if (state.structureClobberState() == StructuresAreWatched) {
- if (JSObject* knownBase = node->child1()->dynamicCastConstant<JSObject*>()) {
+ if (JSObject* knownBase = node->child1()->dynamicCastConstant<JSObject*>(graph.m_vm)) {
if (graph.isSafeToLoad(knownBase, offset))
return true;
}
return true;
}
+ case SetAdd:
+ case MapSet:
+ return false;
+
case LastNodeType:
RELEASE_ASSERT_NOT_REACHED();
return false;
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
-
-#endif // DFGSafeToExecute_h
-