diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGSafeToExecute.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGSafeToExecute.h')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSafeToExecute.h | 320 |
1 files changed, 254 insertions, 66 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h index b6cd5dc08..a9e6a6b89 100644 --- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h +++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-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 @@ -23,10 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGSafeToExecute_h -#define DFGSafeToExecute_h - -#include <wtf/Platform.h> +#pragma once #if ENABLE(DFG_JIT) @@ -48,29 +45,45 @@ public: switch (edge.useKind()) { case UntypedUse: case Int32Use: - case RealNumberUse: + case DoubleRepUse: + case DoubleRepRealUse: + case Int52RepUse: case NumberUse: + case RealNumberUse: case BooleanUse: case CellUse: + case CellOrOtherUse: case ObjectUse: + case ArrayUse: + case FunctionUse: case FinalObjectUse: + case RegExpObjectUse: + case ProxyObjectUse: + case DerivedArrayUse: + case MapObjectUse: + case SetObjectUse: case ObjectOrOtherUse: case StringIdentUse: case StringUse: + case StringOrOtherUse: + case SymbolUse: case StringObjectUse: case StringOrStringObjectUse: + case NotStringVarUse: case NotCellUse: case OtherUse: - case MachineIntUse: + case MiscUse: + 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; - - case KnownNumberUse: - if (m_state.forNode(edge).m_type & ~SpecFullNumber) + + case KnownBooleanUse: + if (m_state.forNode(edge).m_type & ~SpecBoolean) m_result = false; return; @@ -83,6 +96,11 @@ public: if (m_state.forNode(edge).m_type & ~SpecString) m_result = false; return; + + case KnownPrimitiveUse: + if (m_state.forNode(edge).m_type & ~(SpecHeapTop & ~SpecObject)) + m_result = false; + return; case LastUseKind: RELEASE_ASSERT_NOT_REACHED(); @@ -99,8 +117,15 @@ private: // Determines if it's safe to execute a node within the given abstract state. This may // return false conservatively. If it returns true, then you can hoist the given node -// up to the given point and expect that it will not crash. This doesn't guarantee that -// the node will produce the result you wanted other than not crashing. +// up to the given point and expect that it will not crash. It also guarantees that the +// node will not produce a malformed JSValue or object pointer when executed in the +// given state. But this doesn't guarantee that the node will produce the result you +// wanted. For example, you may have a GetByOffset from a prototype that only makes +// semantic sense if you've also checked that some nearer prototype doesn't also have +// a property of the same name. This could still return true even if that check hadn't +// been performed in the given abstract state. That's fine though: the load can still +// safely execute before that check, so long as that check continues to guard any +// user-observable things done to the loaded value. template<typename AbstractStateType> bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) { @@ -109,18 +134,28 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) if (!safeToExecuteEdge.result()) 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. + switch (node->op()) { case JSConstant: - case WeakJSConstant: + case DoubleConstant: + case Int52Constant: + case LazyJSConstant: case Identity: case ToThis: case CreateThis: case GetCallee: + case GetArgumentCountIncludingThis: + case GetRestLength: case GetLocal: case SetLocal: + case PutStack: + case KillStack: + case GetStack: case MovHint: case ZombieHint: - case GetArgument: + case ExitOK: case Phantom: case Upsilon: case Phi: @@ -136,9 +171,9 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case BitURShift: case ValueToInt32: case UInt32ToNumber: - case Int32ToDouble: case DoubleAsInt32: case ArithAdd: + case ArithClz32: case ArithSub: case ArithNegate: case ArithMul: @@ -148,33 +183,59 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case ArithAbs: case ArithMin: case ArithMax: + case ArithPow: + case ArithRandom: case ArithSqrt: + case ArithFRound: + case ArithRound: + case ArithFloor: + case ArithCeil: + case ArithTrunc: case ArithSin: case ArithCos: + case ArithTan: + case ArithLog: 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 CheckExecutable: + case GetExecutable: case GetButterfly: + case CallDOMGetter: + case CallDOM: + case CheckDOM: case CheckArray: case Arrayify: case ArrayifyToStructure: case GetScope: - case GetMyScope: - case SkipTopScope: case SkipScope: - case GetClosureRegisters: + case GetGlobalObject: case GetClosureVar: case PutClosureVar: case GetGlobalVar: - case PutGlobalVar: - case VariableWatchpoint: - case VarInjectionWatchpoint: - case CheckFunction: - case AllocationProfileWatchpoint: + case GetGlobalLexicalVariable: + case PutGlobalVariable: + case CheckCell: + case CheckBadCell: + case CheckNotEmpty: + case CheckStringIdent: case RegExpExec: case RegExpTest: case CompareLess: @@ -182,56 +243,84 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case CompareGreater: case CompareGreaterEq: case CompareEq: - case CompareEqConstant: case CompareStrictEq: - case CompareStrictEqConstant: + 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 LoadVarargs: + case CallForwardVarargs: + case ConstructForwardVarargs: case NewObject: case NewArray: case NewArrayWithSize: case NewArrayBuffer: + case NewArrayWithSpread: + case Spread: case NewRegexp: - case Breakpoint: - case ProfileWillCall: - case ProfileDidCall: - case CheckHasInstance: + case ProfileType: + case ProfileControlFlow: + case CheckTypeInfoFlags: + case ParseInt: + case OverridesHasInstance: case InstanceOf: + case InstanceOfCustom: + case IsEmpty: case IsUndefined: case IsBoolean: case IsNumber: - case IsString: case IsObject: + case IsObjectOrNull: case IsFunction: + case IsCellWithType: + case IsTypedArrayView: case TypeOf: case LogicalNot: + case CallObjectConstructor: case ToPrimitive: case ToString: + case ToNumber: + case NumberToStringWithRadix: + case SetFunctionName: + case StrCat: + case CallStringConstructor: case NewStringObject: case MakeRope: case In: + case HasOwnProperty: case CreateActivation: - case TearOffActivation: - case CreateArguments: - case PhantomArguments: - case TearOffArguments: - case GetMyArgumentsLength: - case GetMyArgumentByVal: - case GetMyArgumentsLengthSafe: - case GetMyArgumentByValSafe: - case CheckArgumentsNotCreated: - case NewFunctionNoCheck: + case CreateDirectArguments: + case CreateScopedArguments: + case CreateClonedArguments: + case GetFromArguments: + case GetArgument: + case PutToArguments: case NewFunction: - case NewFunctionExpression: + case NewGeneratorFunction: + case NewAsyncFunction: case Jump: case Branch: case Switch: case Return: + case TailCall: + case DirectTailCall: + case TailCallVarargs: + case TailCallForwardVarargs: case Throw: - case ThrowReferenceError: + case ThrowStaticError: case CountExecution: case ForceOSRExit: case CheckWatchdogTimer: + case LogShadowChickenPrologue: + case LogShadowChickenTail: case StringFromCharCode: case NewTypedArray: case Unreachable: @@ -240,20 +329,83 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: case LoopHint: - case Int52ToDouble: - case Int52ToValue: - case StoreBarrier: - case ConditionalStoreBarrier: - case StoreBarrierWithNullCheck: case InvalidationPoint: case NotifyWrite: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: case CheckInBounds: case ConstantStoragePointer: case Check: + case MultiPutByOffset: + case ValueRep: + case DoubleRep: + case Int52Rep: + case BooleanToNumber: + case FiatInt52: + case GetGetter: + case GetSetter: + case GetEnumerableLength: + case HasGenericProperty: + case HasStructureProperty: + case HasIndexedProperty: + case GetDirectPname: + case GetPropertyEnumerator: + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: + case ToIndexString: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomNewGeneratorFunction: + 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 CreateRest: + case StringReplace: + case StringReplaceRegExp: + case GetRegExpObjectLastIndex: + case SetRegExpObjectLastIndex: + case RecordRegExpCachedResult: + case GetDynamicVar: + case PutDynamicVar: + case ResolveScope: + case MapHash: + case ToLowerCase: + case GetMapBucket: + case LoadFromJSMapBucket: + case IsNonEmptyMapBucket: return true; - + + case ArraySlice: { + // 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: @@ -272,22 +424,61 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) return node->arrayMode().modeForPut().alreadyChecked( graph, node, state.forNode(graph.varArgChild(node, 0))); - case StructureTransitionWatchpoint: - return state.forNode(node->child1()).m_futurePossibleStructure.isSubsetOf( - StructureSet(node->structure())); - - case PutStructure: - case PhantomPutStructure: case AllocatePropertyStorage: case ReallocatePropertyStorage: - return state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf( - StructureSet(node->structureTransitionData().previousStructure)); + return state.forNode(node->child1()).m_structure.isSubsetOf( + RegisteredStructureSet(node->transition()->previous)); case GetByOffset: - case PutByOffset: - return state.forNode(node->child1()).m_currentKnownStructure.isValidOffset( - graph.m_storageAccessData[node->storageAccessDataIndex()].offset); + case GetGetterSetterByOffset: + case PutByOffset: { + PropertyOffset offset = node->storageAccessData().offset; + + if (state.structureClobberState() == StructuresAreWatched) { + if (JSObject* knownBase = node->child1()->dynamicCastConstant<JSObject*>(graph.m_vm)) { + if (graph.isSafeToLoad(knownBase, offset)) + return true; + } + } + StructureAbstractValue& value = state.forNode(node->child1()).m_structure; + if (value.isInfinite()) + return false; + for (unsigned i = value.size(); i--;) { + if (!value[i]->isValidOffset(offset)) + return false; + } + return true; + } + + case MultiGetByOffset: { + // We can't always guarantee that the MultiGetByOffset is safe to execute if it + // contains loads from prototypes. If the load requires a check in IR, which is rare, then + // we currently claim that we don't know if it's safe to execute because finding that + // check in the abstract state would be hard. If the load requires watchpoints, we just + // check if we're not in a clobbered state (i.e. in between a side effect and an + // invalidation point). + for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) { + GetByOffsetMethod method = getCase.method(); + switch (method.kind()) { + case GetByOffsetMethod::Invalid: + RELEASE_ASSERT_NOT_REACHED(); + break; + case GetByOffsetMethod::Constant: // OK because constants are always safe to execute. + case GetByOffsetMethod::Load: // OK because the MultiGetByOffset has its own checks for loading from self. + break; + case GetByOffsetMethod::LoadFromPrototype: + // Only OK if the state isn't clobbered. That's almost always the case. + if (state.structureClobberState() != StructuresAreWatched) + return false; + if (!graph.isSafeToLoad(method.prototype()->cast<JSObject*>(), method.offset())) + return false; + break; + } + } + return true; + } + case LastNodeType: RELEASE_ASSERT_NOT_REACHED(); return false; @@ -300,6 +491,3 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) - -#endif // DFGSafeToExecute_h - |